和数组不同的是,slice之间不能比较,我们不能使用==操作符来判断两个slice是否相等。

自己总结了下原因:
slice在源码中,其实是一个struct,由三部分组成:指针,长度和容量。

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}
  • 如果==使用的是浅度相等,只要两个slice的指针,长度和容量三个字段相等,那么两个slice就相等。但这样和数组不同的相等测试方法,会让人困惑。

    func main() {
        // 两个数组相等
        a1 := [3]int{1,2,3}
        a2 := [3]int{1,2,3}
        fmt.Println(a1 == a2)    // true
        // 如果slice使用的是浅相等
        a1 := []int{1,2,3}
        a2 := []int{1,2,3}
        fmt.Println(a1 == a2)   // false,和数组的行为不同,造成困惑
    }
  • 如果==使用的是深度相等,和数组的行为保持一致,那也会有下面的问题。
    正常情况下,将一个slice赋值给另一个slice时,我们只是复制上面的结构体,两个slice的指针都指向同一个底层数组。

    func main() {
        s1 := s0
        s1[0] = 0   // 通过s1修改,会影响到s0
    }

    当将slice作为map的key时,我们遵循上面的slice复制规则,只会复制结构体内的指针,长度和容量,不会复制指针指向的底层数组,这是浅拷贝,map在对比两个key是否相等时,使用的会是浅度相等,这就会和深度相等矛盾。

下面有一个例子,如果能够使用slice做为map的key,不同的程序员对程序的输出会有不同的期望,造成困惑。

m := make(map[[]int]bool)
s0 := []int{6, 7, 8}
s1 := []int{6, 7, 8}
s2 := s0
m[s0] = true
s2[0] = 9
println(m[s0])
println(m[s1])
println(m[s2])

参考资料

Why can't Go slice be used as keys in Go maps pretty much the same way arrays can be used as keys?

Last modification:September 6th, 2020 at 12:21 pm
如果觉得我的文章对你有用,请尽情赞赏 🐶