结构切片的属性作为函数参数而不分配切片

时间:2019-07-23 13:20:05

标签: go

我有一片看起来像这样的结构

type KeyValue struct {
  Key   uint32
  Value uint32
}

var mySlice []Keyvalue

此切片mySlice的长度可以可变。

我想将此切片的所有元素传递给具有此签名的函数:

takeKeyValues(keyValue []uint32)

现在,我可以轻松分配一个[]uint32的切片,并用mySlice中元素的所有键/值填充它,然后将该切片作为参数传递到takeKeyValues()中。

但是我试图通过直接传递堆栈上的所有键/值来找到一种无需分配堆的方法。有一些语法技巧可以使我做到这一点吗?

3 个答案:

答案 0 :(得分:4)

没有安全的方法来任意重新解释数据的内存布局。由性能决定是否值得使用不安全的类型转换由您决定。

由于KeyValue的字段大小相等且该结构没有填充,因此您可以将KeyValue元素的基础数组转换为uint32的数组。

takeKeyValues((*[1 << 30]uint32)(unsafe.Pointer(&s[0]))[:len(s)*2])

https://play.golang.org/p/Jjkv9pdFITu

答案 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),但我可以提出另一种方法:

  1. 增加所需元素的上限。
  2. 声明具有该大小的数组类型的变量(不是切片)。
  3. “修补”该数组中所需的所有元素(从索引0开始)。
  4. “切片”数组并将切片传递给被调用者。

切片数组不会复制内存,它只会获取数组第一个元素的地址。

类似这样的东西:

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时,它不必将其分配到堆栈中。基本上,我相信语言规范不会告诉您有关堆栈与堆的任何信息。