切片作为地图中的关键

Is it possible to use slices as keys?

There is my attempt:

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

the compiler gives me an error invalid map key type []string. So either it's not possible or I declared it incorrectly (if so, what would be a correct way?).

No, slices cannot be used as map keys as the have no equality defined.

However, it is possible to use arrays as map keys:

package main

import "fmt"

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

Volker already told that this is not possible and I will give a little bit more details of why is it so with examples from the spec.


Map spec tells you:

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.

It already tells you that the slice can't be a key, but you could have checked it also in the comparison spec:

Slice, map, and function values are not comparable.


This means that also slice can't be a key, an array can be a key. For example you can write:

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

One way to get around this problem is to actually create a key from a slice which has well defined comparison operators:

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

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

In a similar fashion you would have to create functions for creating keys of slices with type different to string.

Depending on your requirements and the complexity of your data, you could use a string as a map key and then use a hash of your slice as the map key.

The nice thing is you can use this technique with anything that can be converted to or from a slice of bytes.

Here's a quick way to convert your slice of strings into a slice of bytes:

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

Here's an example using 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
}

Working version