Ломтик как ключ на карте

Можно ли использовать срезы в качестве ключей?

Есть моя попытка:

h := map[[]string]string{
  []string{"a", "b"} : "ab",
}

компилятор дает мне ошибку invalid map key type []string. Так что либо это невозможно, либо я объявил это неправильно (если да, то был бы правильный путь?).

Ответ 1

Нет, срезы не могут использоваться в качестве ключей карты, поскольку они не имеют определенного равенства.

Ответ 2

Однако в качестве ключей карты можно использовать массивы:

package main

import "fmt"

func main() {
    m := make(map[[2]int]bool)
    m[[2]int{1, 2}] = false
    fmt.Printf("%v", m)
}

Ответ 3

Volker уже сказал, что это невозможно, и я расскажу немного подробнее о том, почему это так с примерами из спецификации.


Спецификация карты сообщает вам:

Операторы сравнения == и!= должны быть полностью определены для операндов ключевого типа; таким образом, тип ключа не должен быть функцией, картой или срез.

Он уже говорит вам, что срез не может быть ключом, но вы могли бы проверить его также в сравнительной спецификации:

Значения среза, карты и функции не сопоставимы.


Это означает, что также срез не может быть ключом, массив может быть ключом. Например, вы можете написать:

h := map[[2]string]string{
  [2]string{"a", "b"} : "ab",
}

Ответ 4

В зависимости от ваших требований и сложности ваших данных вы можете использовать строку в качестве ключа карты, а затем использовать хэш своего фрагмента в качестве ключа карты.

Приятно, что вы можете использовать эту технику для всего, что можно преобразовать в или из куска байтов.

Вот быстрый способ преобразования вашего фрагмента строк в кусок байта:

[]byte(strings.Join([]string{},""))

Вот пример использования SHA1:

type ByteSliceMap struct {
    buf *bytes.Buffer
    m   map[string][]byte
}

func (b *ByteSliceMap) key(buf []byte) string {
    h := sha1.New()
    h.Write(buf)
    sum := h.Sum(nil)
    return fmt.Sprintf("%x", sum)
}

func (t *ByteSliceMap) value(key []byte) (value []byte, ok bool) {
    value, ok = t.m[t.key(key)]
    return
}


func (t *ByteSliceMap) add(key, value []byte) {
    if t.m == nil {
        t.m = make(map[string][]byte)
    }
    t.m[t.key(key)] = value
}

Рабочая версия

Ответ 5

Один из способов обойти эту проблему - фактически создать ключ из среза, который имеет хорошо определенные операторы сравнения:

func createKey(s []string) string { return fmt.Sprintf("%q", s) }

m := make(map[string]string)
s := []string{"a","b"}
m[createKey(s)] = "myValue"

Аналогичным образом вам придется создавать функции для создания ключей срезов с типом, отличным от строки.