Skip to content

Day 013 — Structs & Struct Tags

Month 1 · Week 2 · ⬅ Day 012 · Day 014 ➡ · Journal index

🎯 Learning Objective

Declare structs, choose value vs pointer semantics, embed for composition, and drive JSON with struct tags.

📚 Topics

  • Struct declaration & value semantics
  • Embedding (composition over inheritance)
  • Struct tags + encoding/json

📖 Reading / Sources

📝 Notes

  • A struct is a fixed set of named fields. Structs are values: assignment/passing copies all fields → [[struct-value-semantics]].
  • Two structs are comparable with == only if all fields are comparable (no slice/map/func fields).
  • Embedding an anonymous field promotes its fields/methods to the outer struct — composition, not inheritance → [[embedding]].
  • Method receivers: a pointer receiver can mutate the struct and avoids copying; a value receiver gets a copy. Be consistent per type; if any method needs a pointer receiver, give them all pointer receivers → [[receivers]].
  • Struct tags are string metadata read via reflection. For encoding/json: json:"name" renames, json:",omitempty" drops zero values, json:"-" excludes the field → [[struct-tags]].
  • Only exported (capitalized) fields are marshaled/unmarshaled; unexported fields are invisible to encoding/json → [[exported-fields]].
  • encoding/json ignores unknown keys on Unmarshal by default; pass a pointer (&v) so it can write into your value.
  • The empty struct struct{}{} carries no data (0 bytes) — handy for set values and signal channels.

💻 Code Examples

type User struct {
    Name     string   `json:"name"`
    Email    string   `json:"email,omitempty"` // dropped when ""
    Password string   `json:"-"`               // never serialized
    Roles    []string `json:"roles"`
}

func (u *User) AddRole(r string) { u.Roles = append(u.Roles, r) } // pointer: mutates

Full code: examples/month-01/structs-tags/main.go · Run: go run ./examples/month-01/structs-tags

🏋️ Exercises / Practice

Exercise Status Link
(reinforced via the structs-tags example) examples/month-01/structs-tags

🐛 Mistakes Made

  • Gave a method a value receiver and wondered why a field "wouldn't update" — it mutated a copy. Switched to a pointer receiver.
  • Left a field lowercase and it vanished from JSON output (unexported → ignored).

❓ Open Questions

  • When is embedding better than a named field? (When you want the inner type's methods promoted; otherwise use a named field for clarity.)

🧠 Active Recall (answer without looking)

  1. Q: What do json:"-" and json:",omitempty" do?
    A

- excludes the field entirely; ,omitempty omits it when it holds its zero value. 2. Q: Why can a value-receiver method not mutate the receiver?

A

It operates on a copy of the struct; changes are discarded. Use a pointer receiver to mutate the original.

🪶 Feynman Reflection

A struct is a labeled record. Copying it copies every field, so to change the original a method must take a pointer. Tags are sticky notes on each field telling libraries like encoding/json how to name or skip it.

🕳️ Knowledge Gaps

  • Custom MarshalJSON/UnmarshalJSON and interfaces — revisit in the interfaces/methods week.

✅ Summary

I can define structs, pick value vs pointer receivers deliberately, compose with embedding, and control JSON output with struct tags.

⏭️ Next Steps / Prep for Tomorrow

  • Day 014: Week 2 review + active recall.

Time spent Difficulty Confidence
90 min 🟦🟦⬜⬜⬜ 🟦🟦🟦⬜⬜

Suggested commit: feat(examples): structs and struct tags (day 013)