Можно ли использовать массив или срез (slice) в качестве ключа в map?

Ответ

Ключевое различие: массив (array) — можно использовать как ключ, а срез (slice) — нельзя.

Почему так?

Ключом в map в Go может быть любой тип данных, который является сравнимым (comparable), то есть для которого определена операция сравнения ==.

  1. Массивы (array) являются сравнимыми, если их элементы тоже сравнимы. Сравнение двух массивов происходит поэлементно. Поэтому их можно использовать в качестве ключей.

    // РАБОТАЕТ
    m := make(map[[2]int]string)
    key := [2]int{10, 20}
    m[key] = "value"
    fmt.Println(m[[2]int{10, 20}]) // Выведет: value
  2. Срезы (slice), с другой стороны, по спецификации языка не являются сравнимыми (их можно сравнивать только с nil). Срез — это, по сути, легковесная структура, содержащая указатель на нижележащий массив, длину и ёмкость. Сравнение указателей не дало бы желаемого результата (сравнения содержимого), поэтому эту операцию для срезов запретили, чтобы избежать ошибок. Как следствие, срезы не могут быть ключами в map.

    // ОШИБКА КОМПИЛЯЦИИ
    // m := make(map[[]int]string) 
    // Получим ошибку: invalid map key type []int

Что делать, если нужно использовать срез как ключ?

Самый правильный подход — пересмотреть архитектуру. Если это абсолютно необходимо, можно преобразовать срез в строку, которая является сравнимым типом:

// Преобразование в строку - частый паттерн для []byte
byteSliceKey := []byte("mykey")
stringKey := string(byteSliceKey)

m := make(map[string]string)
m[stringKey] = "data"