Frontend Labs
⋯

8. Structs and methods: value vs. pointer receivers, embedding

8.1 Struct basics and tags

type Server struct {
	Host string `json:"host"`
	Port int    `json:"port"`
	TLS  bool   `json:"tls,omitempty"`
}

Struct tags are metadata strings parsed by reflection at runtime (encoding/json, encoding/xml, validators, ORMs all read them) — they have zero effect on the compiler beyond being valid string literals.

8.2 Value vs. pointer receivers — the rule that matters

type Counter struct{ n int }

func (c Counter) IncByValue()  { c.n++ }   // mutates a COPY — no visible effect
func (c *Counter) IncByPointer() { c.n++ } // mutates the real struct

Rule of thumb: if any method on a type needs a pointer receiver (to mutate state, or to avoid copying something large), make all methods on that type use pointer receivers, for consistency and because Go's method set rules mean a value of type T only gets the pointer receiver methods promoted automatically when it is addressable — a map value, for instance, is not addressable and this trips people up:

counters := map[string]Counter{"a": {}}
counters["a"].IncByPointer() // compile error — map value not addressable

8.3 Embedding: composition, not inheritance

type Logger struct{ Prefix string }

func (l Logger) Log(msg string) { fmt.Println(l.Prefix, msg) }

type Server struct {
	Logger // embedded — promotes Log() onto Server
	Host   string
}

s := Server{Logger: Logger{Prefix: "[server]"}, Host: "localhost"}
s.Log("starting up") // calls the embedded Logger's method directly

Embedding promotes fields and methods to the outer type, but it is not polymorphism — there's no dynamic dispatch, no super, and the embedded type has no idea it's embedded. It's syntactic sugar for "has-a with automatic delegation," which is exactly the composition-over-inheritance philosophy Go pushes everywhere.

8.4 Real-world example

Day 5 of the 90-day plan asks you to embed a Logger struct into a Server struct — this is the idiom behind virtually every Go SDK's "client with options" pattern: an HTTP client embeds a base transport, adds retry/auth logic, and callers use it exactly like the thing it wraps, because embedding promoted all the underlying methods.


Generated from real-life-golang-guide.md · 8 Oct 2026 16:36