Introduction
Structs are Go's primary mechanism for creating custom types by grouping related data together. Unlike classes in OOP languages, Go structs are simple data containers—behavior is added separately through methods. This separation of data and behavior is a core Go philosophy.
Key Concepts
Struct: A typed collection of fields, each with a name and type.
Value Semantics: Structs are values by default; assignment copies all fields.
Exported Fields: Fields starting with uppercase are visible outside the package.
Anonymous Structs: Structs defined inline without a named type.
Real World Context
Structs model everything: database rows, API responses, configuration, domain entities. The exported/unexported distinction enables encapsulation without private/public keywords. Understanding struct value semantics prevents subtle bugs when modifying data.
Deep Dive
Declaration
gotype User struct { ID int Name string Email string CreatedAt time.Time }
Creating Structs
go// Zero value (all fields initialized) var u User // ID=0, Name="", etc. // Struct literal (by field name - preferred) u := User{ ID: 1, Name: "Alice", } // Struct literal (by position - fragile) u := User{1, "Alice", "a@example.com", time.Now()} // Pointer to struct p := &User{Name: "Bob"} p := new(User) // Returns *User with zero values
Field Access
gou := User{Name: "Alice"} u.Name = "Bob" // Modify field // Pointer access (auto-dereferenced) p := &u p.Name = "Charlie" // Same as (*p).Name
Exported vs Unexported
gotype Account struct { ID int // Exported (visible outside package) Balance int // Exported password string // unexported (package-private) }
Anonymous/Inline Structs
go// Useful for one-off data structures config := struct { Host string Port int }{ Host: "localhost", Port: 8080, }
Common Pitfalls
-
Forgetting struct is a value: Assigning
b := acopies the entire struct. Modifyingbdoesn't affectaunless you use pointers. -
Positional literals breaking: Adding a field to a struct breaks all positional literals. Always use named fields.
-
Large struct copying: Passing large structs by value copies all data. Use pointers for performance.
Best Practices
- Always use named field literals:
User{Name: "Alice"}. - Use pointers to avoid copying large structs.
- Keep unexported fields for internal state; export only the API.
- Consider constructor functions for complex initialization.
Summary
Structs group related fields into custom types. They have value semantics (assignment copies). Fields are exported if capitalized. Use struct literals with named fields for clarity, and pointers when you need to modify or avoid copying data.
Code Examples
type Person struct {
Name string
Age int
Address struct {
City string
Country string
}
}
func main() {
p := Person{
Name: "Alice",
Age: 30,
}
p.Address.City = "Paris"
}