Nested Structs
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 16 of 107.
A nested struct is a struct that contains another named struct as one of its fields. This lets you model complex, hierarchical data by composing smaller, reusable types together.
type Address struct {
Street string
City string
ZIP string
}
type Person struct {
Name string
Age int
Address Address // nested struct
}To access fields in a nested struct, you chain the field names with dots.
p := Person{
Name: "Alice",
Age: 30,
Address: Address{
Street: "123 Main St",
City: "Boston",
ZIP: "02101",
},
}
fmt.Println(p.Address.City) // BostonNesting promotes code reuse. The Address type can be used in multiple structs like Person, Company, or Order without duplicating fields. This approach mirrors real-world relationships where entities contain other entities.
type Company struct {
Name string
Employees int
Address Address // same Address type reused
}You can nest structs multiple levels deep, though keeping hierarchies shallow improves readability. Nested structs are fundamental for building object-oriented data models in Go.
Challenge
EasyLet's build an employee management system that demonstrates how nested structs help model real-world hierarchies. You'll create a structure where employees belong to departments, and departments have location information.
You'll organize your code across two files:
models.go: Define three structs that work together:LocationwithBuilding(string) andFloor(int) fieldsDepartmentwithName(string) and a nestedLocationfieldEmployeewithID(int),Name(string), and a nestedDepartmentfield
main.go: Read employee information from input, create an Employee with properly nested structs, and display the complete employee profile by accessing fields through the nested structure.
The following inputs will be provided:
- Line 1: Employee ID (integer)
- Line 2: Employee name
- Line 3: Department name
- Line 4: Building name
- Line 5: Floor number (integer)
Output format:
Employee: [Name] (ID: [ID])
Department: [DepartmentName]
Location: [Building], Floor [Floor]For example, given 101, Alice Chen, Engineering, Tower A, and 5, your output should be:
Employee: Alice Chen (ID: 101)
Department: Engineering
Location: Tower A, Floor 5Access the nested fields using dot notation to chain through the struct hierarchy (e.g., employee.Department.Location.Building).
Cheat sheet
A nested struct is a struct that contains another named struct as one of its fields, allowing you to model hierarchical data by composing smaller, reusable types.
Defining Nested Structs
type Address struct {
Street string
City string
ZIP string
}
type Person struct {
Name string
Age int
Address Address // nested struct
}Accessing Nested Fields
Use dot notation to chain through the struct hierarchy:
p := Person{
Name: "Alice",
Age: 30,
Address: Address{
Street: "123 Main St",
City: "Boston",
ZIP: "02101",
},
}
fmt.Println(p.Address.City) // BostonReusing Nested Structs
The same nested struct type can be reused across multiple parent structs:
type Company struct {
Name string
Employees int
Address Address // same Address type reused
}Nested structs promote code reuse and mirror real-world relationships where entities contain other entities. You can nest structs multiple levels deep, though keeping hierarchies shallow improves readability.
Try it yourself
package main
import "fmt"
func main() {
// Read employee information
var id int
var name string
var deptName string
var building string
var floor int
fmt.Scanln(&id)
fmt.Scanln(&name)
fmt.Scanln(&deptName)
fmt.Scanln(&building)
fmt.Scanln(&floor)
// TODO: Create an Employee with properly nested structs
// Use the Location, Department, and Employee structs from models.go
// Initialize all nested fields with the input values
// TODO: Print the employee profile using the format:
// Employee: [Name] (ID: [ID])
// Department: [DepartmentName]
// Location: [Building], Floor [Floor]
// Access nested fields using dot notation (e.g., employee.Department.Location.Building)
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool