Map — dynamic key-value container, keys must be comparable. Struct — fixed set of named, typed fields defined at compile time.
Maps are reference types with O(1) average lookups. They're perfect for grouping, counting, or indexing data where the keys aren't known in advance. Maps grow dynamically but cannot be compared with == (except nil check).
1wordCount := make(map[string]int)2for _, w := range strings.Fields(text) {3 wordCount[w]++4}5// safe lookup with comma-ok idiom6if count, ok := wordCount["hello"]; ok {7 fmt.Println("found", count, "times")8}
Structs give you a schema. Every field is known at compile time — IDEs provide autocompletion, the compiler catches type errors, and the memory layout is deterministic. Structs compose via embedding.
1type User struct {2 ID int `json:"id" db:"user_id"`3 Email string `json:"email"`4}56type Admin struct {7 User // embed User8 Role string9}
When to use:
Common mistakes:
map[string]interface{} for complex structures — lose type safety and discoverability.ok — zero values may mask missing data.sync.Map — runtime panic.