Go: Передача указателей массива в gob без копирования?

У меня очень, очень большой массив (а не фрагмент) карт, которые я затем пытаюсь кодировать. Мне действительно нужно избегать создания копии массива, но я не могу понять, как это сделать.

Поэтому у меня есть это:

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 будет размером примерно 10 ГБ. Поэтому он должен избегать копирования.

Но опять же, возможно, копируется только фактическая часть [5], но карты внутри этого являются указателями внутри массива, поэтому массив указателей на карты будет скопирован вместо самих карт? Я понятия не имею об этом - все это очень запутанно.

Есть идеи?

1 ответ

Обратите внимание, что Encoder.Encode будет проходить через interface{}.

func (enc *Encoder) Encode(v interface{}) error {

Это означает какой-то указатель на то, что вы будете передавать ему, как я описал в " что означает interface{} в golang? " (см. также " Почему я не могу назначить *Struct для *Interface? ")

Значение интерфейса не является значением конкретной структуры (поскольку оно имеет размер переменной, это было бы невозможно), но это своего рода указатель (точнее указатель на структуру и указатель на тип )

Это означает, что он не будет копировать полный контент вашей карты (или здесь вашего массива). Поскольку массив является значением, вы можете срезать его, чтобы избежать копирования во время вызова Encode():

err = encoder.Encode(*variable[:])

См. " Go Slices: использование и внутренние компоненты "

Это также синтаксис для создания среза, заданного массивом:

x := [3]string{"Лайка", "Белка", "Стрелка"}
s := x[:] // a slice referencing the storage of x

Если это не сработает, вы можете сохранить *variable (здесь массив: [5]map[string]Searcher), поскольку типы карт являются ссылочными типами, такими как указатели или фрагменты: копия не будет огромной. См. " Карты Go в действии ".

Пока массив будет скопирован при передаче в 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]]

licensed under cc by-sa 3.0 with attribution.