Map Keys

May 11, 2023

The only restriction on map keys is that they must be comparable. The spec explains:

Map types

The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice. If the key type is an interface type, these comparison operators must be defined for the dynamic key values; failure will cause a run-time panic.

map[string]int
map[*T]struct{ x, y float64 }
map[string]interface{}

So in summary, virtually any non-interface type is a valid map key, except functions, slices, or other maps. Use of such an unsupported type will result in a compilation error.

func main() {
	var x map[map[string]string]string
	fmt.Println(x)
}

When compiled:

./test.go:8:12: invalid map key type map[string]string

If the map key is an interface type, then the individual interface values must be comparable, or a runtime panic will occur.

func main() {
	x := map[any]string{}
	x[func() {}] = "func"
	fmt.Println(x)
}

when executed:

panic: runtime error: hash of unhashable type func()

Quotes from The Go Programming Language Specification Version of December 15, 2022

Share this

Related Content

Type identities of compound types

So we now know that types are either identical or different. let’s look at the details, with examples. Type identity … In detail: Two array types are identical if they have identical element types and the same array length. So given: type ( X = [10]int Y = X Z [10]int ) Types X, Y, and [10]int are identical to each other, but not to [9]int or [10]int32. Type Z is also different from all the others, due to the fact that it is a named type.

Map length and capacity

Maps, like arrays and slices, have length. Map types … The number of map elements is called its length. For a map m, it can be discovered using the built-in function len and may change during execution. … This should be straight forward, but let’s consider a couple examples for good measure: x := map[string]int{"a": 1, "b": 2, "c": 3} fmt.Println(len(x)) // 3 var y map[string]float64 fmt.Println(len(y)) // 0 And somewhat deceptively, their capacity can also be set, or at least hinted at, but not read.

Using maps

Today I’m jumping around a bit, for the sake of coherence. Map types … [Map] elements may be added during execution using assignments and retrieved with index expressions; they may be removed with the delete built-in function. A new, empty map value is made using the built-in function make, … Let’s summarize with examples. We’ll dive into details as the relevant portions of the spec come up. To create a map, you use the built-in function make: