如何防止将类型用作地图键?

时间:2016-06-20 07:20:44

标签: dictionary go struct key unique

我有一个可以用作地图键的类型,但我想防止这种情况发生。我假设如果类型包含私有成员,则无法从其他包中进行,但这似乎无论如何都可行。什么是使类型无法用作地图键的最佳方法?

type MyType struct {
    A *A
    b b

    preventUseAsKey ?
}

2 个答案:

答案 0 :(得分:10)

我认为不允许使用某种类型作为密钥的任何好处。它只是一个可能使用或不使用的选项,因为你禁止将它用作地图键,所以类型不会更好或更小或更快。

但是如果你想这样做:Spec: Map types:

  

必须为密钥类型的操作数完全定义comparison operators ==和!=;因此,键类型不能是函数,映射或切片。

因此,如果你违反了comparison operators的条款,你就会隐含地得到你想要的东西。您有structstruct类型的条款:

  

如果所有字段都具有可比性,则结构值具有可比性。如果相应的非blank字段相等,则两个struct值相等。

因此,如果所有字段都具有可比性,那么struct值只能进行比较(因此只能用作地图中的键)。 只需添加类型无法比较的字段。

  

切片,贴图和函数值无法比较。

例如,添加一个类型为切片的字段,您就完成了:

type MyType struct {
    S             string
    i             int
    notComparable []int
}

尝试将上述MyType用作关键字:

m := map[MyType]int{}

您收到编译时错误:

invalid map key type MyType

注意:

我写过没有任何好处,禁止将类型作为密钥。它不止于此:从现在开始,您将无法再对类型的值使用比较运算符(因为额外的,不可比较的字段),例如,你失去了比较这些价值的选择:

p1, p2 := MyType{}, MyType{}
fmt.Println(p1 == p2)

编译时错误:

invalid operation: p1 == p2 (struct containing []int cannot be compared)

请注意,通过一些小技巧,您仍然可以保留类型的可比性质,例如:不导出您的类型,而是包含原始类型的包装类型;并将额外的,不可比较的类型添加到包装类型中,例如:

type myType struct {
    S string
    i int
}

type MyType struct {
    myType
    notComparable []int
}

func main() {
    p1, p2 := MyType{}, MyType{}
    fmt.Println(p1.myType == p2.myType)
}

这样,您的myType可以保持可比性,但仍然阻止导出的包装器MyType类型用作密钥类型。

答案 1 :(得分:4)

您的类型应为not be comparable,以便不适合作为地图密钥。

  

切片,贴图和函数值无法比较

请参阅Key Type

  

值得注意的是,列表中没有切片,贴图和函数;这些类型无法使用==进行比较,也不能用作地图键。

因此,如果你的类型是切片,地图或功能,你应该得到你需要的东西 它可能是一个“别名”(定义一个新的named type):

type StringSliceWrap []string
type MyFunc func(i int)

该别名不会用作地图键。

2017年更新:Brad Fitzpatrick give this tip(在struct中添加一个切片),以确保您的<{1}}类型可比:请参阅play.golang.org

struct

package main // disallowEqual is an uncomparable type. // If you place it first in your struct, you prevent == from // working on your struct without growing its size. (Don't put it // at the end; that grows the size of the struct) type disallowEqual [0]func() type T struct { _ disallowEqual Foo string Bar int } func main() { var t1 T var t2 T println(t1 == t2) } 现在不能用作放大器键!