概念
比较值是非常常见的操作。
常规都会使用 == 操作符,但在有些类型情况下会出现意想不到的错误。
错误案例
type customer struct {
id string
operations []float64
}
func main() {
cust1 := customer{id: "x", operations: []float64{1.5}}
cust2 := customer{id: "x", operations: []float64{1.5}}
fmt.Println(cust1 == cust2)
}
我们期望这段代码也能够输出true。然而,它甚至都没有编译通过:
invalid operation: cust1 == cust2 (struct containing []float64 cannot be compared)
如果两种类型具有可比较性,那我们可以使用这两种运算符(==和!=)来比较两种不同的类型。
在Go中可比较的类型包括:
-
布尔值:== 和 != 可以比较两个布尔类型的值是否相等
-
数字:== 和 != 可以比较两个数字类型的值是否相等。如果两个值具有相同的类型或能够转成成相同的类型,那么这两个操作也是可以正常编译的。
-
字符串:== 和 != 可以比较两个字符串是否相等。我们可以根据字符串的词序使用>=, < 和 > 操作符对两个字符串进行比较。
-
指针:== 和 != 可以比较两个指针是否指向了相同的内存地址或者是否都是nil。
-
通道(channels):== 和 != 可以比较两个通道是否是由同一个make创建的或者两个都是nil
所以,在该列表中没有map和slice。
如果struct和array仅有可比较的类型组成,我们也可以将他们添加到此列表中。
另外,特别注意interface{}类型中使用 == 和 !=操作符可能存在的问题。它将导致一个运行时panic:
panic: runtime error: comparing uncomparable type main.customer
解决方法
如果我们不得不对slice、map、或者包含不能比较类型的struct进行比较的时候,该怎么办呢?
1. 使用标准库的方法
比如 如果想比较两个字节切片,我们可以使用bytes.Compare函数。
2. 使用反射和reflect.DeepEqual
该方法会比较两个元素是否是深度相等的。该函数接受的元素是基本类型,数组,结构体,切片(slice),map,指针,接口和函数。
注:由于此函数使用反射,因此会有性能方面的损耗。在本地使用不同大小的结构体进行一些基准测试,reflect.DeepEqual的平均执行速度要比 == 操作符慢100倍。