Go Slices的平等性(同一性) [英] Equality (Identity) of Go Slices

查看:60
本文介绍了Go Slices的平等性(同一性)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与此问题稍有不同检查Go切片的相等性.

My question is slightly different from this question that asks about how to check equality of Go slices.

就像文章所建议的那样,Go切片是 value 由三部分组成:指向数组的指针,段的长度及其容量(段的最大长度).那么,是否有可能(廉价地)检查两个这样的片是否相等,因为它们指向相同的基础数组并且具有相同的长度和容量值(最好不遍历两个片来检查各个元素的相等性)?似乎未在切片上定义 == 运算符.

Like this article suggests, a Go slice is a value consisting of three things: a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment). Is it then possible to (cheaply) check if two such slices are equal because they point to the same underlying array and have the same values for length and capacity (preferably without traversing the two slices checking for equality of individual elements)? It appears that the == operator is not defined on slices.

问题是在我实现位向量( IntSet )时出现的,该向量内部使用 [] uint64 表示元素,而我偶然发现了实现方法 func(* IntSet)等于(* IntSet)bool ,可以称为 s.Equals(s).

The question came while I was implementing a bit vector (IntSet) that internally uses a []uint64 to represent the elements and I stumbled upon implementing a method func (*IntSet) Equals(that *IntSet) bool which could be called like s.Equals(s).

(看来我可以针对这种情况进行优化,如下所示,但问题仍然存在:

(It appears that I could optimize for that case as shown below, but the question remains:

func (this *IntSet) Equals(that *IntSet) bool {
    if this == that { // use equality of pointers!
        return true
    }
// omitted for brevity 
}

推荐答案

使用第一个元素的地址

最简单的方法是简单地获取切片的第一个元素的地址并进行比较(指针为地址运算符即可获取第一个元素的地址,例如& s [0] .如果切片为空,则没有第一个元素,在这种情况下,我们仅检查两个元素是否为空.我们还必须比较切片的长度:

Using the address of the first element

The easiest way is to simply get the address of the first element of the slices, and compare them (pointers are comparable). We can get the address of the first element by simply using the address operator, e.g. &s[0]. If the slices are empty, there is no first element, in which case we only check if both are empty. We also have to compare the lengths of the slices:

func identical(s1, s2 []int) bool {
    if len(s1) != len(s2) {
        return false
    }

    return len(s1) == 0 || &s1[0] == &s2[0]
}

我故意不比较容量,因为只有在切片后才能发挥作用.

I purposefully left out comparing the capacity as that only plays a role if the slices are resliced.

identical()函数仅检查切片是否相同.即使两个不相同的切片不相同,它们也可能相等(它们可能包含相等的元素).

This identical() function only checks if the slices are identical. 2 non-identical slices may be equal (they may contain equal elements) even if they are not identical.

测试:

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 >像这样输入:

To obtain a reflect.SliceHeader, we may use package unsafe and the unsafe.Pointer type like this:

var s []int = ... // s is a slice

// and h will be its descriptor, of type *reflect.SliceHeader
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))

一个简单的比较器函数,用于检查2个条带是否相同,这意味着它们指向相同的后备阵列并且具有相同的长度(无论其容量如何):

A simple comparator function which checks if 2 slices are identical, meaning they point to the same backing array and have the same length (regardless of their capacity):

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
false

这篇关于Go Slices的平等性(同一性)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆