规则一:两个操作数类型必须相同!必须相同!必须相同!
否则,编译时就会报错。Go 的类型系统非常严格,没有隐式转换,所以一个 int 与 int32 是无法比较的,int 与自定义的 type myint int 也是无法比较的。
规则二:浮点类型运算有误差,所以运算后的比较可能有问题
这是计算机语言普遍有的问题, 即 “0.1 + 0.2 == 0.3" 不成立。所以尽量不要比较浮点类型,要比较时可以取差再与一个接近 0 的浮点数(如 1e-9)比较。
规则三:数组的长度是类型的一部分,不同长度的数组,不能比较
注意,是 不能 比较,是会在编译时发生错误。因为类型不同。
规则四:等长数组的比较按元素逐个比较
数组的比较是按元素逐个比较的,顺序不同的数组不相等。(数组没 > < 的比较)
规则五:引用类型除 slice 和 map 外(即包含指针和 channel)比较的是地址,而不是比较实际值。
type A struct {
a int
}
func main() {
b := &A{1}
c := &A{1}
d := A{1}
e := &d
f := &d
fmt.Println(c == b) // false
fmt.Println(f == e) // true
}
规则六: slice 和 map 只允许与 nil 比较,与其他比较时编译错误
为什么这样规定呢,因为切片是引用类型,它可以间接指向自己
a := []int{1, 2, 3, 4, 5}
a = a[2:3] // 指向自己
fmt.Println(a, len(a), cap(a)) // [3] 1 3,cap 是到数组结束
切片一步递归赋值时直接爆栈;map 亦然;数组OK。
a := [2]interface{}{0, 1} // 数组
a[0] = a // 可以递归赋值
fmt.Println(a) // [[0 1] 1]
b := []interface{}{0, 1} // 切片
b[0] = b // 递归赋值时
fmt.Println(b) // fatal error: stack overflow 爆栈
d := map[int]interface{}{1: 2}
d[1] = d
fmt.Println(d)
// runtime: goroutine stack exceeds 1000000000-byte limit
// fatal error: stack overflow
// 一样爆栈
上面爆栈是在
fmt.Println()
处爆的,而不是递归赋值的位置。
数组不爆栈是因为数组赋值是值拷贝。切片和 map 是改变引用,在输出的时候会递归输出导致爆栈。
规则七:接口类型比较的是基本类型与动态值
var a interface{} = 1
var b interface{} = 1
var c interface{} = 2
var d interface{} = "a"
fmt.Println(a == b) // true,类型相同,值相同
fmt.Println(a == c) // false,类型相同,值不同
fmt.Println(a == d) // false,类型不同
var e interface{} = myint(1) // type myint int
fmt.Println(a == e) // false,类型不同,值量相同
规则八:接口类型的基本类型不可比较时,强行比较发生 panic
var a interface{} = []int{2}
var b interface{} = []int{2}
fmt.Println(a == b) // panic: runtime error: comparing uncomparable type []int
规则九:接口值的比较只要相互可以转化就可以比较
var f *os.File // f
var g *os.File // g 是另一个变量
var f_r io.Reader = f //
var f_rc io.ReadCloser = f //
var g_rc io.ReadCloser = g //
fmt.Println(f_r == f_rc) // 可以比较,true
fmt.Println(f_rc == g_rc) // 可以比较,true,这个尚不清楚
规则十:任何含有不可比较类型的类型是不可比较的
如,当结构体中含有切片时、数组元素中含有切片时、指针指向切片时,他们都不可以比较,map 亦然。编译报错
规则十一:zero-width struct
的指针比较不保证比较的正确性
zero-width struct
是没有任何属性的结构体,即 struct{}{}
。他们的指针比较可能为 true,也可能是 false。
alias 之后如 type People struct{}
也一样。
规则十二:用 reflect.DeepEqual
比较任何值
包括切片、map、Func,以及包含这些类型属性的结构体。
网友评论