对于命名类型/结构体,是否可以定义相等性?

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

Is it possible to define equality for named types/structs?

问题

在阅读了一个关于在Go中使用切片作为map键的相关问题后,我对Go中的相等性产生了好奇。

我知道在Java的Object中可以重写equals方法。在Go中是否有类似的方法来定义如何检查用户定义的类型/结构体的相等性?如果有的话,那么就可以解决上述问题。我尝试使用interface{},但是收到了错误消息panic: runtime error: hash of unhashable type []int

英文:

After reading a related question about using slices in maps, I became curious about equality in Go.

I know it's possible to override the equals method of a Java Object. Is there a similar way to define how Go checks user defined types/structs for equality? If so, there would be a workaround for the issue referenced above. I thought using interface{} values might offer a solution but I received the error message panic: runtime error: hash of unhashable type []int.

答案1

得分: 33

不。你不能修改等号运算符,并且没有内置的方法来添加对自定义类型使用==语法的支持。相反,你应该使用reflect.DeepEqual来比较指针值。

Go支持检查结构体的相等性。

type Person struct {
    Name string
}

a := Person{"Bill DeRose"}
b := Person{"Bill DeRose"}

a == b // true

对于指针字段(以你想要的方式),它不起作用,因为指针地址是不同的。

type Person struct {
    Friend *Person
}

a := Person{Friend: &Person{}}
b := Person{Friend: &Person{}}

a == b // false

你可以导入reflect包,并使用reflect.DeepEqual来比较。

import "reflect"

a := Person{Friend: &Person{}}
b := Person{Friend: &Person{}}

reflect.DeepEqual(a, b) // true

请记住,这里有一些注意事项。

通常,DeepEqual是Go的==运算符的递归放宽。然而,这个想法是不可能实现的,因为会存在一些不一致性。具体来说,一个值可能与自身不相等,要么是因为它是func类型(一般情况下是不可比较的),要么是因为它是浮点数的NaN值(在浮点数比较中不等于自身),要么是因为它是包含这样的值的数组、结构体或接口。

英文:

No. You can't modify the equality operator and there is no built-in way to add support for custom types to use == syntax. Instead you should compare the pointer values using reflect.DeepEqual.

Go supports equality checking structs.

type Person struct {
    Name string
}

a := Person{"Bill DeRose"}
b := Person{"Bill DeRose"}

a == b // true

It won't work with pointer fields (in the way you want) because the pointer addresses are different.

type Person struct {
    Friend *Person
}

a := Person{Friend: &Person{}}
b := Person{Friend: &Person{}}

a == b // false


import "reflect"

a := Person{Friend: &Person{}}
b := Person{Friend: &Person{}}

reflect.DeepEqual(a, b) // true

Keep in mind there are caveats.

> In general DeepEqual is a recursive relaxation of Go's == operator. However, this idea is impossible to implement without some inconsistency. Specifically, it is possible for a value to be unequal to itself, either because it is of func type (uncomparable in general) or because it is a floating-point NaN value (not equal to itself in floating-point comparison), or because it is an array, struct, or interface containing such a value.

答案2

得分: 27

不,这是不可由用户定义的。Go语言对于相等性有严格的规定,甚至对于可比性也有规定,而可比性本身是基于可赋值性的。请参考规范中的比较运算符部分

英文:

No, this is not user-definable. Go has strict rules what counts as equal, and even what is comparable which itself is based on assignability. Take a look at the Comparison operators section of the spec.

答案3

得分: 10

Go语言本身没有标准的比较方法(截至go 1.13)。

然而,比较工具可以提供自己的方式来支持比较。

函数cmp.Equal(来自google/go-cmp/cmp)通过定义一个Equal方法来支持自定义类型比较器:

• 如果值具有形式为(T) Equal(T) bool(T) Equal(I) bool的Equal方法,其中T可赋值给I,则使用x.Equal(y)的结果,即使xy为nil。否则,不存在这样的方法,评估将继续到下一个规则。

英文:

There's no standard in Go language itself, yet (go 1.13).

However, comparison utilities could provide their own way to support it.

Function cmp.Equal (from google/go-cmp/cmp) supports definition of custom type comparator via definition of a Equal method:

> • If the values have an Equal method of the form "(T) Equal(T) bool" or "(T) Equal(I) bool" where T is assignable to I, then use the result of x.Equal(y) even if x or y is nil. Otherwise, no such method exists and evaluation proceeds to the next rule.

huangapple
  • 本文由 发表于 2013年12月1日 15:21:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/20309751.html
匿名

发表评论

匿名网友

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

确定