arrays - slice 的别名

标签 arrays pointers go memory slice

如何检查两个 slice 是否由同一个数组备份?

例如:

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

alias(b, c) == true

别名应该是什么样子?

最佳答案

一般来说,您无法判断后备数组是否在 2 个 slice 之间共享,因为使用 full slice expression ,可以控制生成的 slice 的容量,这样即使检查容量也不会出现重叠。

例如,如果您有一个包含 10 个元素的后备数组,则可能会创建一个仅包含前 2 个元素的 slice ,并且其容量可能为 2。并且可能会创建另一个仅包含最后 2 个元素的 slice ,其容量再次为 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))

上面将打印 x 的长度和容量和y是 2。它们显然具有相同的支持数组,但您没有任何方法可以告诉它。


编辑:我误解了这个问题,下面描述了如何判断两个 slice (的元素)是否重叠。

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

不幸的是,指针没有排序,我们无法应用 <>它们上的运算符(Go中有指针,但没有指针算术)。检查第一个 slice 的所有元素地址是否与第二个 slice 中的任何地址匹配,这是不可行的。

但是我们可以获得一个指针值(地址),其类型为 uintptr使用 Reflect 包,更具体地说 Value.Pointer() 方法(或者我们也可以使用包 unsafe 来做到这一点,但 reflect 是“更安全”),和 uintptr值是整数,它们是有序的,因此我们可以比较它们。

所以我们能做的就是获取 slice 的第一个和最后一个元素的地址,通过比较它们,我们可以判断它们是否重叠。

这是一个简单的实现:

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 上尝试一下.

关于arrays - slice 的别名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53280378/

相关文章:

python - 删除 numba.lowering.LoweringError : Internal error

javascript - 比较和过滤两个数组

c - 指针的奇怪行为

c++ - C++ 链表中的虚拟节点

json - 如何将嵌套的 JSON 解析为 Go 中的结构?

c# - C#错误中数组元素的访问器

php - 将逗号分隔的文本从输入中插入到数据库中,而没有重复的条目

c - 试图修复有关 ‘const’ 限定符的警告

google-app-engine - Go 的 Google App Engine 数据存储区没有 != 过滤器

go - 为什么Logrus将日志写入Linux日志?