繁体   English   中英

切片别名

[英]Aliasing of slices

如何检查两个切片是否由同一阵列备份?

例如:

a := []int{1, 2, 3}
b := a[0:1]
c := a[2:3]

alias(b, c) == true

alias应如何显示?

通常,您无法确定2个切片之间是否共享了支持数组,因为使用完整切片表达式 ,一个数组可能会控制所得切片的容量,因此即使检查容量也不会有重叠。

例如,如果您有一个包含10个元素的支持数组,则可能会创建一个仅包含前2个元素的切片,其容量可能是2。并且可能会创建另一个仅保留其后2个元素及其容量的切片。再次是2。

请参阅以下示例:

a := [10]int{}

x := a[0:2:2]
y := a[8:10:10]

fmt.Println("len(x) = ", len(x), ", cap(x) = ", cap(x))
fmt.Println("len(y) = ", len(y), ", cap(y) = ", cap(y))

上面的代码将打印出xy长度和容量均为2。它们显然具有相同的后备数组,但是您将没有任何办法来说明这一点。


编辑:我误解了这个问题,下面介绍如何判断2个切片的(元素)是否重叠。

没有语言支持,但是由于切片具有某个后备数组的连续部分,因此我们可以检查其元素的地址范围是否重叠。

不幸的是,指针不能以不能在其上应用<>运算符的方式排序(Go中有指针,但是没有指针算术)。 并且检查第一个切片的元素的所有地址是否与第二个切片的任何地址匹配,这是不可行的。

但是我们可以使用反射包,更具体地说是Value.Pointer()方法(或者也可以使用包unsafe ,但reflect是“更安全”的)来获取指针值(地址)作为uintptr一种类型。 uintptr值是整数,它们是有序的,因此我们可以对其进行比较。

因此,我们可以做的是获取切片的第一个和最后一个元素的地址,并通过比较它们来确定它们是否重叠。

这是一个简单的实现:

func overlap(a, b []int) bool {
    if len(a) == 0 || len(b) == 0 {
        return false
    }

    amin := reflect.ValueOf(&a[0]).Pointer()
    amax := reflect.ValueOf(&a[len(a)-1]).Pointer()
    bmin := reflect.ValueOf(&b[0]).Pointer()
    bmax := reflect.ValueOf(&b[len(b)-1]).Pointer()

    return !(amax < bmin || amin > bmax)
}

测试它:

a := []int{0, 1, 2, 3}
b := a[0:2]
c := a[2:4]
d := a[0:3]

fmt.Println(overlap(a, b)) // true
fmt.Println(overlap(b, c)) // false
fmt.Println(overlap(c, d)) // true

Go Playground上尝试一下。

在这里找到了一种方法。 我的想法是,尽管我不认为有办法找到支持数组的起点,但ptr + slice的cap应该[*]指向数组的结尾。 因此,然后比较最后一个指针是否相等,例如:

func alias(x, y nat) bool {
    return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
}

[*]该代码包含以下注释:

注意:别名假定基础数组的容量不会更改nat值。 也就是说,此代码中没有3操作数切片表达式(或更糟糕的是,基于反射的操作具有相同的效果)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM