То, что вы хотите - это, по сути, глубокая копия, которая не поддерживается стандартной библиотекой.
Ваш выбор:
- Сделайте копию "вручную", например, создайте новую структуру и скопируйте поля, в которых указатели или фрагменты / карты / каналы / и т. д. должны дублироваться вручную, рекурсивным способом.
Это проще всего сделать, назначив вашу структуру другой, которая копирует все поля, так что вам, по сути, нужно только лелеять указатели / карты / фрагменты и т. Д. (Но рекурсивно).
- Использовать внешнюю библиотеку, например,
github.com/mohae/deepcopy
, github.com/ulule/deepcopier
или github.com/mitchellh/copystructure
- Маршаллируйте вашу структуру в некоторый формат (например, JSON), затем демаршируйте в другую переменную.
Последний вариант может выглядеть так:
var i1 Item
data, err := json.Marshal(i1)
if err != nil {
panic(err)
}
var i2 Item
if err := json.Unmarshal(data, &i2); err != nil {
panic(err)
}
// i2 holds a deep copy of i1
Обратите внимание, что маршалинг / демаршалинг не особенно эффективен, но прост и компактен. Также обратите внимание, что это может плохо обрабатывать рекурсивные структуры данных, может даже зависать или паниковать (например, поле указывает на содержащую структуру), но обработка рекурсивных структур может быть проблемой для всех решений. Также обратите внимание, что это не приведет к клонированию неэкспортированных полей.
Хорошая особенность этого маршалинга / демаршалинга в том, что вы можете легко создать вспомогательную функцию для глубокого копирования «любых» значений:
func deepCopy(v interface{}) (interface{}, error) {
data, err := json.Marshal(v)
if err != nil {
return nil, err
}
vptr := reflect.New(reflect.TypeOf(v))
err = json.Unmarshal(data, vptr.Interface())
if err != nil {
return nil, err
}
return vptr.Elem().Interface(), err
}
Тестирование:
p1 := image.Point{X: 1, Y: 2}
fmt.Printf("p1 %T %+v\n", p1, p1)
p2, err := deepCopy(p1)
if err != nil {
panic(err)
}
p1.X = 11
fmt.Printf("p1 %T %+v\n", p1, p1)
fmt.Printf("p2 %T %+v\n", p2, p2)
Вывод (попробуйте на Go Playground ):
p1 image.Point (1,2)
p1 image.Point (11,2)
p2 image.Point (1,2)