# Start With the Mental Model
Structs hold data. Methods add behavior. Interfaces describe behavior. Embedding lets you reuse behavior.
- Struct = data shape
- Method = behavior on that data
- Interface = contract (behavior only)
- Embedding = composition and reuse
# Structs
Structs group fields together. The zero value of a struct is usable immediately (all fields are zeroed).
type User struct {
Name string
Email string
Age int
}
u1 := User{Name: "Alice", Email: "alice@go.dev", Age: 30}
var u2 User // zero value
fmt.Println(u2.Name, u2.Age) // "", 0# Methods and Receivers
Methods are functions with receivers. Value receivers operate on a copy. Pointer receivers can mutate.
type Counter struct { count int }
func (c *Counter) Inc() { c.count++ }
func (c Counter) Value() int { return c.count }
c := Counter{}
c.Inc()
fmt.Println(c.Value())Use pointer receivers when you need mutation or want to avoid copying large structs.
# Interfaces
Interfaces describe behavior. Any type that has the methods automatically satisfies the interface.
type Shape interface {
Area() float64
}
type Rect struct { W, H float64 }
func (r Rect) Area() float64 { return r.W * r.H }
func printArea(s Shape) {
fmt.Println(s.Area())
}Small interfaces are easier to test and reuse. Define interfaces where they are used, not where they are implemented.
# The Nil Interface Trap
An interface is nil only if both its type and value are nil. A typed nil pointer inside an interface is not nil.
type MyErr struct{}
func (e *MyErr) Error() string { return "boom" }
func f() error {
var e *MyErr = nil
return e // NOT nil interface
}Fix by returning a literal `nil` instead of a typed nil.
# Embedding (Composition)
Embedding promotes fields and methods from the embedded type to the outer type. This is composition, not inheritance.
type Logger struct{}
func (Logger) Log(msg string) {}
type Server struct {
Logger // embedded
}
s := Server{}
s.Log("hi")⚡ Key Takeaways
- Structs hold data; methods add behavior.
- Pointer receivers enable mutation and avoid large copies.
- Interfaces are satisfied implicitly, so design small interfaces.
- Embedding is composition and promotes methods.
- Nil interface is a common pitfall — type and value must be nil.