如何在golang中创建具有动态长度而不是切片的数组?

时间:2018-06-27 07:13:30

标签: arrays go slice

例如:我想使用反射来获取切片的数据作为操作它的数组。

func inject(data []int) {
    sh := (*reflect.SliceHeader)(unsafe.Pointer(&data))
    dh := (*[len(data)]int)(unsafe.Pointer(sh.Data))
    printf("%v\n", dh)
}

由于len(data)不是常数,此函数将产生编译错误。我该如何解决?

1 个答案:

答案 0 :(得分:4)

要添加到@icza的注释中,您可以使用&data[0]轻松提取基础数组-假设data是初始化的切片。哎呀,这里没有必要跳过障碍:第一个slice的元素的地址实际上是slice的基础数组中第一个插槽的地址-在这里没有魔术。

由于创建数组元素的地址而创建 对内存的引用-只要垃圾回收器是 有关-您可以放心地让切片本身超出范围 而不必担心该阵列的内存无法访问。

唯一无法真正完成结果的事情 指针传递取消引用的结果。 这仅仅是因为Go中的数组的长度被编码为 它们的类型,因此您将无法创建一个函数来接受 这样的数组-因为您事先不知道数组的长度。

现在请停下来思考。

从切片中提取支持数组后, 指向数组内存的指针。 要明智地随身携带,您还需要随身携带 数组的长度……但这正是切片的作用: 他们将支持数组的地址与 数据(还有容量)。

因此,我真的认为您应该重新考虑您的问题 从我的立场来看,我倾向于认为这不是问题 首先。

种情况下,使用指向后备数组的指针 从切片中提取可能会有所帮助:例如,在“合并”时 这样的数组(例如,通过sync.Pool)以减少内存流失 在某些情况下,但这是具体问题。 如果您有具体问题,请说明 不是您尝试的解决方案-@Flimzy说了什么。


更新,我认为我应该更好地解释

  

您无法真正处理结果   指针绕过取消引用它的结果。

位。

关于Go中数组(与切片相反)的关键点 是数组(就像Go中的所有内容)都被传递了 按值,对于数组,这意味着将复制其数据。

也就是说,如果有

var a, b [8 * 1024 * 1024]byte
...
b = a

语句b = a实际上将复制8 MiB数据。 函数参数显然也是如此。

切片通过握住指针避开了此问题 到基础(支持)数组。所以分片价值 有点struct类型,包含 一个指针和两个整数。 因此,复制它确实很便宜,但可以“交换”它 具有参考语义:原始值和 它的副本指向相同的后备数组-即, 引用相同的数据。

我真的建议您阅读这两篇文章, 按照指示的顺序:

  1. https://blog.golang.org/go-slices-usage-and-internals
  2. https://blog.golang.org/slices