Go 语言中的 struct 相等性比较
在 Go 中,做相等性比较要比很多其它语言简单的多。
在很多语言中,如果想比较相等性:
首先需要让类型 Equatable(也就是可以比较,可能需要实现一些相等性比较的接口)
其次还需要让类型 Hashable(让其可以作为 Map 中的 Key)。
而Go 不是这样的。在 Go 中,只要类型具有可以预测的内存布局(Memory Layout),那么相等性比较就可以自动的实现,也就是可以使用 ==、!= 运算符,并可以作为 Map 的 Key。
例子:
本例中,两个 name 类型的变量 name1 和 name2:
因为它们是同一种类型
并且其字段组成从内存角度看具备可预测性
所以它们可以比较相等性。
该例程序编译通过,由于所有字段的值是相等的,所以 name1 和 name2 就是相等。
例子:如果我把 name2 中 first 字段的值改为 Nick1:
那么 name1 和 name2 就不相等了,程序就没有任何输出了。这个很好理解。
综上,name1 和 name2 能比较相等性的原因就是:
name 类型是由两个 string 类型的字段组成的
而 string 从内存布局角度看具备可预测性,所以 name 类型从内存角度也具备可预测性。
例子:如果我在 name 类型中添加一个 slice 类型的字段 middle:
那么,在比较 name1 和 name2 相等性的时候(也就是 ifname1 == name2 或者 !=),编译器会报错。错误提示写到“== 运算符在 name 类型上没有定义”。
这是为什么?
因为 slice 是基于数组工作的,如果向 slice 里面添加过多的元素,那么就需要重新分配内存,把原来的值复制到新的内存里。因此,slice 从内存布局角度并不具备可预测性。所以会出现以上错误。
不仅是 slice 类型,例如 map、func 等字段类型也会导致 name 无法比较相等性。
例子:
如果两个类型的内存布局一样,但是类型不一样会怎么样?
例子:
类型 name 和类型 id 的字段组成是一样的,可以理解为它们具有同样的内存布局。但是在比较相等性时,编译器仍然会报错,因为它们不是同一种类型。