我有一个可以用作地图键的类型,但我想防止这种情况发生。我假设如果类型包含私有成员,则无法从其他包中进行,但这似乎无论如何都可行。什么是使类型无法用作地图键的最佳方法?
type MyType struct {
A *A
b b
preventUseAsKey ?
}
答案 0 :(得分:10)
我认为不允许使用某种类型作为密钥的任何好处。它只是一个可能使用或不使用的选项,因为你禁止将它用作地图键,所以类型不会更好或更小或更快。
但是如果你想这样做:Spec: Map types:
必须为密钥类型的操作数完全定义comparison operators ==和!=;因此,键类型不能是函数,映射或切片。
因此,如果你违反了comparison operators的条款,你就会隐含地得到你想要的东西。您有struct
个struct
类型的条款:
如果所有字段都具有可比性,则结构值具有可比性。如果相应的非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)
}
现在不能用作放大器键!