比如:我想用reflect把一个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)
不是常量。我该如何解决?
最佳答案
添加到 @icza的注释,您可以使用 &data[0]
轻松提取底层数组——假设 data
是一个初始化的 slice 。 IOW,这里没有必要跳过箍:第一个 slice 元素的地址实际上是 slice 底层数组中第一个槽的地址——这里没有魔法。
由于获取数组元素的地址正在创建 对该内存的引用——只要垃圾收集器是 关注——你可以安全地让 slice 本身超出范围 不用担心该阵列的内存变得无法访问。
唯一你不能真正用结果做的事情 指针正在传递取消引用它的结果。 这仅仅是因为 Go 中的数组将它们的长度编码为 他们的类型,所以你将无法创建一个函数来接受 这样的数组——因为你事先不知道数组的长度。
现在请停下来想一想。
从 slice 中提取支持数组后,您有 指向数组内存的指针。 为了明智地随身携带它,您还需要随身携带 数组的长度……但这正是 slice 的作用: 他们将后备数组的地址与 其中的数据(以及容量)。
因此我真的认为你应该重新考虑你的问题 从我的立场来看,我倾向于认为这不是问题 开始。
在情况下,使用指向后备数组的指针
从 slice 中提取可能有帮助:例如,当“池化”
这样的数组(比如,通过 sync.Pool
)来减少内存流失
在某些情况下,但这些都是具体问题。
如果您遇到具体问题,请解释,
不是您尝试的解决方案——@Flimzy 所说的。
更新 我想我应该更好地解释
you can't really do with the resulting pointer is passing around the result of dereferencing it.
位。
关于 Go 中数组的一个关键点(相对于 slice ) 是数组——就像 Go 中的所有东西一样——被传递 按值,对于数组,这意味着它们的数据被复制。
也就是说,如果你有
var a, b [8 * 1024 * 1024]byte
...
b = a
b = a
语句实际上会复制 8 MiB 的数据。
显然这同样适用于函数的参数。
slice 通过持有指针来回避这个问题
到底层(支持)阵列。所以 slice 值
是一个小的 struct
类型,包含
一个指针和两个整数。
因此,复制它确实很便宜,但“作为交换”
具有引用语义:原始值和
它的副本指向同一个后备数组——也就是说,
引用相同的数据。
我真的建议你阅读这两篇文章, 按照指定的顺序:
关于arrays - 如何在 golang 中创建具有动态长度而不是 slice 的数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51056652/