有一些引用类型比如切片,map无法用== 判断,golang提供DeepEqual内置方法来比较,下面介绍具体原理
切片
方法中判断切片是否相等具体代码如下,可以看出满足下面两点
1.两个切片len长度相等
2.指向同一个内存地址,即数据源是同一个 or 每一个位置对应元素都相等,两者满足一个就行
case Slice:
if v1.IsNil() != v2.IsNil() {
return false
}
if v1.Len() != v2.Len() {
return false
}
if v1.Pointer() == v2.Pointer() {
return true
}
for i := 0; i < v1.Len(); i++ {
if !deepValueEqual(v1.Index(i), v2.Index(i), visited) {
return false
}
}
return true
上面示例满足指针不相同但是每个元素相同,所以结果为true,另外可以看出即使切片的cap不相等也不影响,源码中没有对cap做限制
struct
如果两个结构体的属性不一样,包括 1.顺序不一样 2.某个属性名称不一样 3.属性个数不一样 4.struct 命名不一样 都会导致两个结构体的type不一致,源码注释中有一句话
// Values of distinct types are never deeply equal.
两个不同type的值永远是不相等的
所以结构体 属性不相同的情况下,type是不同的,直接会在type判断的时候就返回false,具体代码
func DeepEqual(x, y interface{}) bool {
if x == nil || y == nil {
return x == y
}
v1 := ValueOf(x)
v2 := ValueOf(y)
if v1.Type() != v2.Type() { //到这里就会返回
return false
}
return deepValueEqual(v1, v2, make(map[visit]bool))
}
struct如果是显式命名不一致,说明不是同一个struct,也不一样
如果两个结构体来自于同一个结构体定义,判断type的时候,肯定是true的,如下
值的type里面有很多信息需要校验
测试发现
1.顺序不一致,会导致ptrdata不一样
2.属性名称不一样,比如一个属性值是name ,另一个是name1 ,导致hash不一样
3.属性个数不一样,导致size,ptrdata等多个参数都不一样
4.struct名字不一样,hash不一样
代码下面的deepValueEqual 方法 是具体会判断属性对应的值是否相等的逻辑,结构体type不一致都不会走到这里
如果属性都一样的情况下,进行属性对应值校验的逻辑,比较具体源码如下
case Struct:
for i, n := 0, v1.NumField(); i < n; i++ {
if !deepValueEqual(v1.Field(i), v2.Field(i), visited) {
return false
}
}
return true
走到这里说明属性的情况都是一样的,比如第一个属性都是name,第二个是age,在这里就是比较每个属性里面具体的值是否相等
注意:struct里面如果不包含map slice等不能用== 比较的值的时候,可以用==判断
比如下面是可以的
下面就会编译不通过
报错
invalid operation: sm1 == sm2 (struct containing map[string]string cannot be compared)
用注释代码就不会报错
map
从源码可以就看出来
1.先比较键值对数
2.然后比较指针,如果是同一个数据源,直接返回true
3.不是同一数据源,比较每一个key对应的val都相同,返回true
case Map:
if v1.IsNil() != v2.IsNil() {
return false
}
if v1.Len() != v2.Len() {
return false
}
if v1.Pointer() == v2.Pointer() {
return true
}
for _, k := range v1.MapKeys() {
val1 := v1.MapIndex(k)
val2 := v2.MapIndex(k)
if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(val1, val2, visited) {
return false
}
}
return true
注意:map中即使键值对顺序不一样,也可以相等,因为map本来就是无序的,所以赋值顺序不重要
func
只有在两个函数都是nil的情况下才是相等,返回true
case Func:
if v1.IsNil() && v2.IsNil() {
return true
}
// Can't do better than this:
return false