我有一片看起来像这样的结构
type KeyValue struct {
Key uint32
Value uint32
}
var mySlice []Keyvalue
此切片mySlice
的长度可以可变。
我想将此切片的所有元素传递给具有此签名的函数:
takeKeyValues(keyValue []uint32)
现在,我可以轻松分配一个[]uint32
的切片,并用mySlice
中元素的所有键/值填充它,然后将该切片作为参数传递到takeKeyValues()
中。
但是我试图通过直接传递堆栈上的所有键/值来找到一种无需分配堆的方法。有一些语法技巧可以使我做到这一点吗?
答案 0 :(得分:4)
没有安全的方法来任意重新解释数据的内存布局。由性能决定是否值得使用不安全的类型转换由您决定。
由于KeyValue
的字段大小相等且该结构没有填充,因此您可以将KeyValue
元素的基础数组转换为uint32
的数组。
takeKeyValues((*[1 << 30]uint32)(unsafe.Pointer(&s[0]))[:len(s)*2])
答案 1 :(得分:1)
作为JimB答案的替代方法,您还可以使用reflect
(reflect.SliceHeader)和unsafe
(unsafe.Pointer)包来实现此目的。
https://play.golang.org/p/RLrMgoWgI7t
s := []KeyValue{{0, 100}, {1, 101}, {2, 102}, {3, 103}}
var data []uint32
sh := (*reflect.SliceHeader)(unsafe.Pointer(&data))
sh.Data = uintptr(unsafe.Pointer(&s[0]))
sh.Len = len(s) * 2
sh.Cap = sh.Len
fmt.Println(data)
答案 2 :(得分:0)
我对您想要的东西感到困惑。如果切片是动态的,则必须在添加元素(在调用站点)时动态对其进行生长。
Go没有alloca(3)
,但我可以提出另一种方法:
切片数组不会复制内存,它只会获取数组第一个元素的地址。
类似这样的东西:
func caller(actualSize int) {
const MaxLen = 42
if actualSize > MaxLen {
panic("actualSize > MaxLen")
}
var kv [MaxLen]KeyValue
for i := 0; i < actualSize; i++ {
kv[i].Key, kv[i].Value = 100, 200
}
callee(kv[:actualSize])
}
func callee(kv []KeyValue) {
// ...
}
但是请注意,当Go编译器看到var kv [MaxLen]KeyValue
时,它不必将其分配到堆栈中。基本上,我相信语言规范不会告诉您有关堆栈与堆的任何信息。