我的问题与询问如何检查Go切片的相等性的这个问题略有不同。
就像这个文章建议的那样,Go片是一个值,它由三部分组成:指向数组的指针、段的长度以及它的容量(段的最大长度)。那么,是否可以(便宜地)检查两个这样的切片是否相等,因为它们指向相同的基础数组,并且具有相同的长度和容量值(最好不用遍历两个切片来检查单个元素的相等性)?似乎没有在片上定义==运算符。
这个问题是在我实现一个bit向量(IntSet)时提出的,它在内部使用一个[]uint64来表示元素,我偶然发现了一个方法func (*IntSet) Equals(that *IntSet) bool,它可以被称为s.Equals(s)。
(看来我可以对这种情况进行优化,如下所示,但问题仍然存在:
func (this *IntSet) Equals(that *IntSet) bool {
if this == that { // use equality of pointers!
return true
}
// omitted for brevity
}发布于 2018-10-26 13:46:34
使用第一个元素的地址
最简单的方法是简单地获取切片的第一个元素的地址,并比较它们(指针是可比较)。我们只需使用地址运算符,例如&s[0],就可以获得第一个元素的地址。如果片是空的,则没有第一个元素,在这种情况下,我们只检查两者是否都是空的。我们还必须比较切片的长度:
func identical(s1, s2 []int) bool {
if len(s1) != len(s2) {
return false
}
return len(s1) == 0 || &s1[0] == &s2[0]
}我故意忽略了比较容量,因为只有当切片被重新分配时,这才起作用。
此identical()函数仅检查切片是否相同。2不相同的切片可能是相等的(它们可能包含相同的元素),即使它们不是相同的。
测试它:
s := []int{1, 2, 3}
fmt.Println(identical(s, s))
s2 := []int{1, 2, 3}
fmt.Println(identical(s, s2))输出是(在围棋游乐场上尝试它):
true
false使用reflect.SliceHeader
我们可以选择获取和使用包含指针、长度和容量的片描述符。这是用reflect.SliceHeader建模的
type SliceHeader struct {
Data uintptr
Len int
Cap int
}要获得reflect.SliceHeader,我们可以使用包unsafe和如下所示的unsafe.Pointer类型:
var s []int = ... // s is a slice
// and h will be its descriptor, of type *reflect.SliceHeader
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))一个简单的比较器函数,它检查两个切片是否相同,这意味着它们指向相同的支持数组并具有相同的长度(不管它们的容量如何):
func identical(s1, s2 []int) bool {
h1 := (*reflect.SliceHeader)(unsafe.Pointer(&s1))
h2 := (*reflect.SliceHeader)(unsafe.Pointer(&s2))
return h1.Data == h2.Data && h1.Len == h2.Len
}测试它:
s := []int{1, 2, 3}
fmt.Println(identical(s, s))
s2 := []int{1, 2, 3}
fmt.Println(identical(s, s2))输出(在围棋游乐场上尝试):
true
falsehttps://stackoverflow.com/questions/53009686
复制相似问题