Go:将数组的指针传递给gob而不复制?

时间:2014-08-03 05:47:32

标签: pointers go

我有一个非常非常大的数组(不是切片),我正在尝试编码。我真的需要避免复制数组,但我无法弄清楚如何做到这一点。

所以我到目前为止:

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]部分,但是这里的地图是数组内的指针,所以指向地图的指针数组会被复制而不是地图本身?我对此一无所知 - 这一切都让人非常困惑。

有什么想法吗?

1 个答案:

答案 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?")

  

接口值不是具体结构的值(因为它具有可变大小,这是不可能的),但它是一种指针(更确切地说是一种指针)指向结构的指针和指向类型的指针

http://i.stack.imgur.com/H78Bz.png

这意味着它不会复制地图的完整内容(或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]]