英文:
Go cmp - how to define custom equality for a map with a struct as its keys?
问题
给定一个以结构体作为键的地图,其中结构体的值是指向另一个结构体的指针:
type Dog struct {
Name string
}
type Cat struct {
Name string
}
type MapKey struct {
dog *Dog
cat *Cat
}
myMap := make(map[MapKey]int)
我该如何使用cmp包使下面的地图相等,其中它们被认为是相等的,因为MapKey具有相同的值(使用reflect.DeepEquals或cmp.Equals)?
keyOne := MapKey{
&Dog{Name: "bob"},
&Cat{Name: "clive"},
}
keyTwo := MapKey{
&Dog{Name: "bob"},
&Cat{Name: "clive"},
}
got := map[MapKey]int{
keyOne: 1,
}
want := map[MapKey]int{
keyTwo: 1,
}
在cmp文档中,它说我可以使用cmpopts.SortMaps(https://pkg.go.dev/github.com/google/go-cmp/cmp#Equal),但我不明白这与我的情况有何关系。
我尝试在MapKey结构上定义一个自定义的Equals函数,但它从未被调用。
可以使用Go Playground重现此问题:
https://go.dev/play/p/qMxaya3S26M
英文:
Given a map that uses a struct as its key, where the values of the struct are pointers to another struct:
type Dog struct {
Name string
}
type Cat struct {
Name string
}
type MapKey struct {
dog *Dog
cat *Cat
}
myMap := make(map[MapKey]int)
How would I use the cmp package to make the below maps equal, where they are considered equal because the MapKey has the same values (reflect.DeepEquals or cmp.Equals)?
keyOne := MapKey{
&Dog{Name: "bob"},
&Cat{Name: "clive"},
}
keyTwo := MapKey{
&Dog{Name: "bob"},
&Cat{Name: "clive"},
}
got := map[MapKey]int{
keyOne: 1,
}
want := map[MapKey]int{
keyTwo: 1,
}
In the cmp documentation, it says I could use cmpopts.SortMaps (https://pkg.go.dev/github.com/google/go-cmp/cmp#Equal), however I don't see how this is relevant to my scenario.
I've tried defining a custom Equals function on the MapKey struct but it never gets called.
Go playground to reproduce this:
https://go.dev/play/p/qMxaya3S26M
答案1
得分: 1
cmp.Equal
是使用map[MapKey]int
类型的参数调用的,而不是MapKey
类型。
因此,自定义的Equal
函数必须在map[MapKey]int
类型上进行定义。
但是,为了定义这个函数,我们需要从map[MapKey]int
定义一个新类型。
这是一个完整工作示例的Playground链接:https://go.dev/play/p/deteHANWQ_3
type MapKeyInt map[MapKey]int
func (m MapKeyInt) Equal(other MapKeyInt) bool {
if len(m) != len(other) {
return false
}
keys, keysOther := make([]MapKey, 0), make([]MapKey, 0)
values, valuesOther := make([]int, 0), make([]int, 0)
for k, v := range m {
keys = append(keys, k)
values = append(values, v)
}
for k, v := range other {
keysOther = append(keysOther, k)
valuesOther = append(valuesOther, v)
}
for i := 0; i < len(m); i++ {
if (keys[i].dog.Name != keysOther[i].dog.Name) || (keys[i].cat.Name != keysOther[i].cat.Name) {
return false
}
if values[i] != valuesOther[i] {
return false
}
}
return true
}
英文:
The cmp.Equal
is called with parameters of type map[MapKey]int
, not MapKey
So the custom Equal
function has to be defined on the type map[MapKey]int
.
But to define this function, we need to define a new type from map[MapKey]int
.
Here's a playground to the full working example: https://go.dev/play/p/deteHANWQ_3
type MapKeyInt map[MapKey]int
func (m MapKeyInt) Equal(other MapKeyInt) bool {
if len(m) != len(other) {
return false
}
keys, keysOther := make([]MapKey, 0), make([]MapKey, 0)
values, valuesOther := make([]int, 0), make([]int, 0)
for k, v := range m {
keys = append(keys, k)
values = append(values, v)
}
for k, v := range other {
keysOther = append(keysOther, k)
valuesOther = append(valuesOther, v)
}
for i := 0; i < len(m); i++ {
if (keys[i].dog.Name != keysOther[i].dog.Name) || (keys[i].cat.Name != keysOther[i].cat.Name) {
return false
}
if values[i] != valuesOther[i] {
return false
}
}
return true
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论