Создание копии структур в GO
Переменная со структурой в Go может быть легко скопирована в другую переменную с помощью оператора присваивания:
package main import ( "fmt" ) type Dog struct { age int name string } func main() { roger := Dog{5, "Roger"} mydog := roger if roger == mydog { fmt.Println("Roger and mydog are equal structs") } }
mydog и roger - две отдельные переменные, но при сравнении их свойств по свойствам они одинаковы.
Теперь мы можем изменить каждое свойство этих переменных, не затрагивая другой объект, поскольку структура Dog содержит базовые типы, которые копируются по значению.
Если бы у нас был ссылочный тип в нашей структуре, это было не так просто, потому что указатель был скопирован, а не значение, поэтому это было бы поверхностной копией.
Например
type Cat struct { age int name string friends []string }
Список друзей нашей кошки - это срез, ссылочный тип (наряду с указателями, картами, функциями и каналами), поэтому, если у вас есть объект кошки, и вы копируете его, как мы делали для примера Dog выше, вы не могли измените свойство друзей, не затрагивая и другой объект.
Нужна глубокая копия.
Глубокая копия структуры
Вы можете выполнить такую глубокую копию вручную. В случае фрагмента вы можете выполнить копию следующим образом:
package main import ( "fmt" ) type Cat struct { age int name string friends []string } func main() { wilson := Cat{7, "Wilson", []string{"Tom", "Tabata", "Willie"}} nikita := wilson nikita.friends = make([]string, len(wilson.friends)) copy(nikita.friends, wilson.friends) nikita.friends = append(nikita.friends, "Syd") fmt.Println(wilson) fmt.Println(nikita) }
Вышеприведенный код приведет к тому, что wilson будет {7 Wilson [Tom Tabata Willie]} и nikita {7 Wilson [Tom Tabata Willie Syd]}
Таким образом, вы можете видеть, что срез представляет собой совершенно другой объект, а не только ссылку на тот же фрагмент.
Использование библиотеки для глубокого копирования структуры
https://github.com/jinzhu/copier является (одной из многих) библиотек для глубокого копирования. Она упрощает глубокую копию структуры без явного управления каждым полем. Вот пример, все, что нам нужно, это выполнить функцию copier.Copy(&nikita, &wilson), и все готово:
package main import ( "fmt" "github.com/jinzhu/copier" ) type Cat struct { age int name string friends []string } func main() { wilson := Cat{7, "Wilson", []string{"Tom", "Tabata", "Willie"}} nikita := Cat{} copier.Copy(&nikita, &wilson) nikita.friends = append(nikita.friends, "Syd") fmt.Println(wilson) fmt.Println(nikita) }