What does this print? (nil vs empty slices and maps in JSON)
Question 455MediumGo 1.22 to 1.25
type Resp struct {
Items []int `json:"items"`
Meta map[string]int `json:"meta"`
Ptr *int `json:"ptr"`
}
var a []int
b := []int{}
x, _ := json.Marshal(Resp{Items: a})
y, _ := json.Marshal(Resp{Items: b, Meta: map[string]int{}})
fmt.Println(string(x))
fmt.Println(string(y))
var r Resp
json.Unmarshal([]byte(`{"items":null}`), &r)
fmt.Println(r.Items == nil)
Output:
{"items":null,"meta":null,"ptr":null}
{"items":[],"meta":{},"ptr":null}
true
A nil slice/map marshals to null; an empty one to []/{}. Frontend clients doing resp.items.length crash on null, so APIs typically initialize slices (make([]T, 0)) before encoding. On decode, JSON null leaves the slice nil (and for non-pointer scalar fields, null is a no-op, leaving the previous value).
Also: []byte marshals as a base64 string, not an array of numbers — a common surprise.
More on Standard Library, HTTP & Systems Design in Go
- Q453You implemented MarshalJSON but it isn't called. Why? Explain receiver rules and the recursion trap.
- Q454json.Unmarshal vs json.Decoder: when to use each, and how do you safely decode a request body?
- Q456How does database/sql connection pooling work? Which settings matter and what causes connection leaks?
- Q457How do you handle transactions, NULLs and "no rows" correctly with database/sql?
- Q458What is the exact io.Reader contract? What's wrong with this read loop?
- Q459Compose io primitives: upload a file to HTTP while computing its SHA-256 and limiting size, without buffering it in memory.