I have a type that can be used as a map key, but I want to prevent this from occurring. I assumed that if the type contained a private member it wouldn't be possible from other packages, but this appears to work anyway. What's the best way to make the type unusable as a map key?
type MyType struct {
A *A
b b
preventUseAsKey ?
}
Answer
I don't see any benefit of disallowing a type being used as a key. It is just an option which may or may not be used, the type will not be any better or smaller or faster just because you forbid to use it as a map key.
But if you want to do it: Spec: Map types:
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.
So if you can violate the terms of the comparison operators, you implicitly get what you want. You have a struct
, terms for the struct
types:
Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.
So struct
values are only comparable (and thus can only be used as keys in maps) if all their fields are comparable. Simply add a field whose type is not comparable.
Slice, map, and function values are not comparable.
So for example add a field whose type is a slice, and you're done:
type MyType struct {
S string
i int
notComparable []int
}
Attempting to use the above MyType
as a key:
m := map[MyType]int{}
You get a compile-time error:
invalid map key type MyType
Note:
I wrote about not having any benefit of forbidding the type being a key. It's more than that: from now on you won't be able to use comparison operators on values of your type anymore (because of the extra, non-comparable field), so e.g. you lose the option to compare those values:
p1, p2 := MyType{}, MyType{}
fmt.Println(p1 == p2)
Compile-time error:
invalid operation: p1 == p2 (struct containing []int cannot be compared)
Note that with a little trick you could still preserve the comparable nature of your type, e.g. by not exporting your type but a wrapper type which embeds the original one; and add the extra, non-comparable type to the wrapper type, e.g.:
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)
}
This way your myType
can remain comparable but still prevent the exported, wrapper MyType
type to be used as key type.
No comments:
Post a Comment