There was a time before Go 1 when indexing a map with a non-existing key crashed the app. This was changed to return the zero value of the value type of the map. This was a design decision which allows the (limited) use of uninitialized language constructs to be used without extra checks, which simplifies code.
For example you can for range
over nil
slices and nil
maps, you can check their length etc. The result is the same of course: iterating over a nil
slice or map will result in zero iterations, and the length of nil
slices and maps is 0, but you do not need to use an if
statement beforehand to tell if the value is non-nil
(in order to tell if you can range over them or index them).
PeterSO already showed a good example when the zero value for non-existing keys is useful: counters.
Another famous example is a map being used as a set. If you choose the value type to be bool
, you don't have to initialize values that are not in the set. Indexing the map tells if a value (the key) is in the set, and if it's not, the zero value of bool
type being false
will tell you that it's not in the set.
For example:
fruits := map[string]bool{}
// Add elements to the set:
fruits["apple"] = true
fruits["banana"] = true
// Test if elements are in the map:
fmt.Println("Is apple in the set?", fruits["apple"])
fmt.Println("Is banana in the set?", fruits["banana"])
fmt.Println("Is plum in the set?", fruits["plum"])
fmt.Println("Is lemon in the set?", fruits["lemon"])
Output (try it on the Go Playground):
Is apple in the set? true
Is banana in the set? true
Is plum in the set? false
Is lemon in the set? false