【发布时间】:2013-12-16 08:14:33
【问题描述】:
是否可以使用切片作为键?
这是我的尝试:
h := map[[]string]string{
[]string{"a", "b"} : "ab",
}
编译器给我一个错误invalid map key type []string。所以要么不可能,要么我声明不正确(如果是,那么正确的方法是什么?)。
【问题讨论】:
标签: go
是否可以使用切片作为键?
这是我的尝试:
h := map[[]string]string{
[]string{"a", "b"} : "ab",
}
编译器给我一个错误invalid map key type []string。所以要么不可能,要么我声明不正确(如果是,那么正确的方法是什么?)。
【问题讨论】:
标签: go
但是,使用数组作为映射键是possible:
package main
import "fmt"
func main() {
m := make(map[[2]int]bool)
m[[2]int{1, 2}] = false
fmt.Printf("%v", m)
}
【讨论】:
string 可以用作键,例如map[string]bool - 一个字节片不能 map[[]byte]bool。但是 string 和 []byte 可以互换转换 - 所以这有效:bs := []byte{0xde, 0xad, 0xbe, 0xef} ; mymap[string(bs)] = true
不,切片不能用作映射键,因为它们没有定义相等性。
【讨论】:
Volker 已经告诉过这是不可能的,我将通过规范中的示例详细说明为什么会这样。
Map spec告诉你:
必须为操作数完全定义比较运算符 == 和 != 密钥类型;因此键类型不能是函数、映射或 切片。
它已经告诉你切片不能是键,但你也可以在 comparison spec 中检查它:
切片、映射和函数值不可比较。
这意味着切片也不能是键,数组可以是键。例如你可以写:
h := map[[2]string]string{
[2]string{"a", "b"} : "ab",
}
【讨论】:
根据您的要求和数据的复杂性,您可以使用字符串作为映射键,然后使用切片的哈希作为映射键。
好消息是您可以将此技术用于任何可以转换为字节切片的内容。
这是将字符串切片转换为字节切片的快速方法:
[]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
}
【讨论】:
string(myByteSlice) 就足够了。转换执行动态分配(-> GC)。散列部分可以重构为不执行分配(通过使用数组和使用例如 Segment 的 fasthash)。
解决此问题的一种方法是从具有明确定义的比较运算符的切片中实际创建一个键:
func createKey(s []string) string { return fmt.Sprintf("%q", s) }
m := make(map[string]string)
s := []string{"a","b"}
m[createKey(s)] = "myValue"
以类似的方式,您必须创建函数来创建类型不同于字符串的切片键。
【讨论】: