Go cmp – 如何为以结构体为键的映射定义自定义相等性?

huangapple go评论119阅读模式
英文:

Go cmp - how to define custom equality for a map with a struct as its keys?

问题

给定一个以结构体作为键的地图,其中结构体的值是指向另一个结构体的指针:

  1. type Dog struct {
  2. Name string
  3. }
  4. type Cat struct {
  5. Name string
  6. }
  7. type MapKey struct {
  8. dog *Dog
  9. cat *Cat
  10. }
  11. myMap := make(map[MapKey]int)

我该如何使用cmp包使下面的地图相等,其中它们被认为是相等的,因为MapKey具有相同的值(使用reflect.DeepEquals或cmp.Equals)?

  1. keyOne := MapKey{
  2. &Dog{Name: "bob"},
  3. &Cat{Name: "clive"},
  4. }
  5. keyTwo := MapKey{
  6. &Dog{Name: "bob"},
  7. &Cat{Name: "clive"},
  8. }
  9. got := map[MapKey]int{
  10. keyOne: 1,
  11. }
  12. want := map[MapKey]int{
  13. keyTwo: 1,
  14. }

在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:

  1. type Dog struct {
  2. Name string
  3. }
  4. type Cat struct {
  5. Name string
  6. }
  7. type MapKey struct {
  8. dog *Dog
  9. cat *Cat
  10. }
  11. 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)?

  1. keyOne := MapKey{
  2. &Dog{Name: "bob"},
  3. &Cat{Name: "clive"},
  4. }
  5. keyTwo := MapKey{
  6. &Dog{Name: "bob"},
  7. &Cat{Name: "clive"},
  8. }
  9. got := map[MapKey]int{
  10. keyOne: 1,
  11. }
  12. want := map[MapKey]int{
  13. keyTwo: 1,
  14. }

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

  1. type MapKeyInt map[MapKey]int
  2. func (m MapKeyInt) Equal(other MapKeyInt) bool {
  3. if len(m) != len(other) {
  4. return false
  5. }
  6. keys, keysOther := make([]MapKey, 0), make([]MapKey, 0)
  7. values, valuesOther := make([]int, 0), make([]int, 0)
  8. for k, v := range m {
  9. keys = append(keys, k)
  10. values = append(values, v)
  11. }
  12. for k, v := range other {
  13. keysOther = append(keysOther, k)
  14. valuesOther = append(valuesOther, v)
  15. }
  16. for i := 0; i < len(m); i++ {
  17. if (keys[i].dog.Name != keysOther[i].dog.Name) || (keys[i].cat.Name != keysOther[i].cat.Name) {
  18. return false
  19. }
  20. if values[i] != valuesOther[i] {
  21. return false
  22. }
  23. }
  24. return true
  25. }
英文:

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

  1. type MapKeyInt map[MapKey]int
  2. func (m MapKeyInt) Equal(other MapKeyInt) bool {
  3. if len(m) != len(other) {
  4. return false
  5. }
  6. keys, keysOther := make([]MapKey, 0), make([]MapKey, 0)
  7. values, valuesOther := make([]int, 0), make([]int, 0)
  8. for k, v := range m {
  9. keys = append(keys, k)
  10. values = append(values, v)
  11. }
  12. for k, v := range other {
  13. keysOther = append(keysOther, k)
  14. valuesOther = append(valuesOther, v)
  15. }
  16. for i := 0; i &lt; len(m); i++ {
  17. if (keys[i].dog.Name != keysOther[i].dog.Name) || (keys[i].cat.Name != keysOther[i].cat.Name) {
  18. return false
  19. }
  20. if values[i] != valuesOther[i] {
  21. return false
  22. }
  23. }
  24. return true
  25. }

huangapple
  • 本文由 发表于 2022年11月7日 21:29:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/74347375.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定