Go 获取切片中值的指针
有没有办法获取指向切片中实际值的指针?我在地图上有一个报价树:Go 获取切片中值的指针,go,Go,有没有办法获取指向切片中实际值的指针?我在地图上有一个报价树: map[uint64]map[uint16][]offer 要通过id(从1到n)快速访问,我需要一片指针: []*优惠 实际报价位于第一棵树中,在切片中应该是指向该实际报价的指针 我无法遍历树并收集实际值的指针,因为这个切片的range给了我一个副本,但我总共有数十亿个这样的结构,副本会浪费我的内存:一个结构的40字节会导致100+gb,将来会更多。我还需要将树中的值片段存储为连续,以便查找报价的事实 是否有某种方法可以使用不
map[uint64]map[uint16][]offer
要通过id(从1到n)快速访问,我需要一片指针:
[]*优惠
实际报价位于第一棵树中,在切片中应该是指向该实际报价的指针
我无法遍历树并收集实际值的指针,因为这个切片的range
给了我一个副本,但我总共有数十亿个这样的结构,副本会浪费我的内存:一个结构的40字节会导致100+gb,将来会更多。我还需要将树中的值片段存储为连续,以便查找报价的事实
是否有某种方法可以使用不安全
或反射
包来获取这些指针
指针索引只生成一次,并且两个结构都是不可变的,仅用于查找提供
更新:
我完全错了。在切片中获取指向元素的指针没有问题。我的代码是:
var offers []offer // actually there was about 50gb of offers
for i := range offers {
currentOffer := offers[i]
s.Relations[currentOffer.Id] = ¤tOffer
}
在这段代码之后,应用程序消耗的ram总量变成了100+gb。我立即想到从值片中提取元素会给我该值的副本,但这是错误的。我只是自己将原始值复制到currentOffer
变量中。这个小错误带走了50gb的内存
实际上,此代码段工作正常:
for i := range offers {
s.Relations[offers[i].Id] = &offers[i]
}
经过一些调查,我得出了以下代码:
package main
import (
"fmt"
"reflect"
"unsafe"
)
type offer struct {
id uint64
}
func main() {
sl := []offer{{1}, {id: 2}}
size := unsafe.Sizeof(offer{})
header := (*reflect.SliceHeader)(unsafe.Pointer(&sl))
for i := 0; i < len(sl); i++ {
offset := uintptr(i) * size
ptr := header.Data + offset
o := (*offer)(unsafe.Pointer(ptr))
o.id = 5
fmt.Println(o)
}
for _, o := range sl {
fmt.Println(o.id)
}
}
这段代码演示了如何访问切片中的实际数据,而不是复制的数据
更新:
通过不安全指针获取指针与通过索引从切片获取常规指针具有相同的效果。不清楚如何以及如何在地图中存储什么。但是,如果您需要通过id快速查找报价,为什么不首先存储它呢
map[uint64][]*offer
?类似的东西?@icza我需要两个索引,一个用于两个键(本例中为uint64和uint16),另一个用于提供的id。报价单只能有一份。第二个索引应作为指向原始报价的指针。@mkopriva按索引访问时,请复制您的脚本报价结构。在我的例子中,它将提供的内存量翻倍,而不翻倍的情况下,提供的内存量已经是50+gb。@SergioTulentsev在主索引中存储实际值使我能够更高效地检索提供的bucket,而不是在存储指针时从稀疏堆内存中收集提供的bucket。在更改片值方面没有区别,但是我通过引用这个值展示了如何做到这一点。在我的例子中,我需要一个值的引用,而不是副本。@abonec:注意go-vet
在这里给你的警告,你真的不应该在go中做指针算术。
&{5}
&{5}
5
5