Map — heterogeneous key-value store with runtime type checking. Struct — homogeneous collection of named fields with compile-time type checking.
Maps are ideal when keys are not known ahead of time (user input, dynamic data). They use hash tables internally, so lookups are O(1) on average. However, maps have overhead per entry and are not safe for concurrent writes.
1config := map[string]string{2 "log_level": "debug",3 "port": "8080",4}5// dynamic key — great for user-provided data6config[os.Getenv("KEY")] = os.Getenv("VALUE")
Structs give you compile-time safety — the compiler knows every field name and type. This catches typos, enables IDE autocompletion, and makes code self-documenting. Structs are also value types, which means no nil-pointer issues.
1type Config struct {2 LogLevel string `json:"log_level"`3 Port string `json:"port"`4}56cfg := Config{LogLevel: "debug", Port: "8080"}7cfg.Log_level = "info" // compile error — typo caught!
When to use:
Common mistakes:
map[string]interface{} to model complex data — use a struct with json tags instead.ok value — silently returns zero value.== (except against nil).