我有一个非常非常大的数组(不是切片),我正在尝试编码。我真的需要避免复制数组,但我无法弄清楚如何做到这一点。
所以我到目前为止:
func doSomething() {
var mygiantvar [5]map[string]Searcher
mygiantvar = Load()
Save(`file.gob.gz`, &mygiantvar)
}
func Save(filename string, variable *[5]map[string]Searcher) error {
// Open file for writing
fi, err := os.Create(filename)
if err !=nil {
return err
}
defer fi.Close()
// Attach gzip writer
fz := gzip.NewWriter(fi)
defer fz.Close()
// Push from the gob encoder
encoder := gob.NewEncoder(fz)
err = encoder.Encode(*variable)
if err !=nil {
return err
}
return nil
}
根据我的理解,将mygiantvar的指针传递给Save,这将保存第一个副本。但是整个数组肯定会被复制到encoder.Encode
中,然后将它复制到更多的函数中,对吗?
这个mygiantvar
变量大小相当于10GB。因此,必须避免被复制。
但是再一次可能只复制了实际的数组[5]部分,但是这里的地图是数组内的指针,所以指向地图的指针数组会被复制而不是地图本身?我对此一无所知 - 这一切都让人非常困惑。
有什么想法吗?
答案 0 :(得分:2)
请注意,Encoder.Encode
会传递interface{}
。
func (enc *Encoder) Encode(v interface{}) error {
这意味着一种指向你将传递给它的任何东西的指针,正如我在" what is the meaning of interface{}
in golang?"中描述的那样;
(另见" Why can't I assign a *Struct
to an *Interface
?")
接口值不是具体结构的值(因为它具有可变大小,这是不可能的),但它是一种指针(更确切地说是一种指针)指向结构的指针和指向类型的指针
这意味着它不会复制地图的完整内容(或your array)。
由于数组是一个值,因此您可以对其进行切片以避免在调用Encode()
期间进行任何复制:
err = encoder.Encode(*variable[:])
请参阅" Go Slices: usage and internals"
这也是给定数组创建切片的语法:
x := [3]string{"Лайка", "Белка", "Стрелка"}
s := x[:] // a slice referencing the storage of x
如果这不起作用,您可以保留*variable
(此处为数组:[5]map[string]Searcher
),因为地图类型是引用类型,如指针或切片:副本不会很大。
请参阅" Go maps in action"。
传递给interface{}
时会复制数组,但地图内容不会被复制。
请参阅此 play.golang.org 示例:
package main
import "fmt"
func main() {
var a [1]map[string]int
a[0] = make(map[string]int)
a[0]["test"] = 0
modify(a)
fmt.Println(a)
}
func modify(arr interface{}) {
a := arr.([1]map[string]int)
a[0]["test"] = -1
}
输出:
[map[test:-1]]