Chapter 46: Go Struct
1. What is a Struct? (The Simplest Explanation)
A struct is:
A named collection of fields — each field has its own name and type. You use a struct when you want to group related data together into one logical unit.
Think of it as a record or a row in a table or a form:
- A Person has name, age, city
- A Book has title, author, pages, year
- An Order has id, items, total, status
2. Basic Syntax – How to Define & Create a Struct
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// 1. Define the struct type (usually outside any function) type Person struct { Name string Age int City string Active bool } // 2. Create values (instances) of the struct func main() { // Style A – zero value (all fields get zero values) var p1 Person fmt.Printf("p1: %+v\n", p1) // {Name: Age:0 City: Active:false} // Style B – field names (order doesn't matter) p2 := Person{ Name: "Webliance", Age: 25, City: "Hyderabad", Active: true, } fmt.Printf("p2: %+v\n", p2) // Style C – positional (order must match definition, no names) p3 := Person{"Ananya", 22, "Bangalore", true} fmt.Printf("p3: %+v\n", p3) // Style D – mix (some fields zero, some set) p4 := Person{Name: "Rahul", City: "Chennai"} fmt.Printf("p4: %+v\n", p4) // Age=0, Active=false } |
Very important style rule (2025–2026 community standard):
- Always use field names when initializing (Person{Name: “…”}) — positional style is error-prone and non-idiomatic when struct has >2–3 fields
- Use zero value when you want defaults
- Use %+v in fmt.Printf to see field names (very helpful when debugging)
3. Accessing & Modifying Fields
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
p := Person{Name: "Webliance", Age: 25} fmt.Println(p.Name) // Webliance fmt.Println(p.Age) // 25 p.Age = 26 // modify field p.Active = true fmt.Printf("Updated: %+v\n", p) |
Dot notation — same as most languages.
4. Embedding (Composition – Go’s way of “inheritance”)
Go has no classical inheritance, but you can embed one struct inside another — this is called embedding or composition.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
type Address struct { City string State string PinCode string } type Employee struct { Name string Age int Address // ← embedded (anonymous field) Department string } func main() { emp := Employee{ Name: "Ananya", Age: 28, Department: "Engineering", Address: Address{ City: "Hyderabad", State: "Telangana", PinCode: "500081", }, } // You can access embedded fields directly (promotion) fmt.Println(emp.City) // Hyderabad fmt.Println(emp.State) // Telangana // Or explicitly fmt.Println(emp.Address.City) } |
Embedding rules (very important):
- You can access embedded fields directly on the outer struct (called field promotion)
- If there is a name conflict → you must use the full path (emp.Address.City)
- Methods of embedded types are also promoted (we’ll see methods later)
5. Struct Pointers – When & Why
Most of the time you work with pointers to structs — especially when:
- You want to modify the struct inside a function
- You want to avoid copying large structs
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
func birthday(p *Person) { p.Age++ // modifies the original struct } func main() { p := Person{Name: "Rahul", Age: 30} birthday(&p) // pass address fmt.Println(p.Age) // 31 } |
Common pattern:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
func NewPerson(name string, age int) *Person { return &Person{ Name: name, Age: age, } } p := NewPerson("Sai", 22) // factory function returning pointer |
6. Anonymous Structs (Inline / One-off)
Sometimes you need a struct just once — no need to give it a name.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
point := struct { X float64 Y float64 }{ X: 3.5, Y: -2.1, } fmt.Printf("Point: %+v\n", point) |
Very common in:
- JSON responses
- Test data
- Quick grouping
7. Real-World Patterns You Will Use Every Day
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// Pattern 1: Configuration type Config struct { Port int Debug bool DatabaseURL string } // Pattern 2: API response type UserResponse struct { ID string `json:"id"` Name string `json:"name"` Email string `json:"email"` CreatedAt time.Time `json:"created_at"` } // Pattern 3: Database row / entity type Product struct { ID int64 Name string Price float64 InStock bool CreatedAt time.Time UpdatedAt time.Time } |
8. Quick Practice – Try Writing These
- Define a Book struct: Title, Author, Pages, Year, IsRead
- Create a function printBook(b Book) that prints nicely
- Create promoteEmployee(e *Employee) that increases salary by 10%
- Embed Address inside Student struct and access city directly
Which struct felt most natural to design?
Any part still confusing?
- Difference between value receiver vs pointer receiver? (we’ll see in methods)
- When to use embedding vs plain field?
- Anonymous structs vs named structs?
- Or ready to move to methods (functions on structs) next?
Keep creating small structs and printing them — structs are the foundation of almost every meaningful data model in Go.
You’re making really solid progress — keep asking! 💪🇮🇳🚀
