К сожалению или нет, в Go нет способа сделать это. Первый инструмент, который приходит на ум, - это отражение (пакет reflect
), но используя отражение, вы можете только читать неэкспортированные поля, но не можете их установить. См. Как клонировать структуру с неэкспортированным полем?
Единственный способ клонировать структуры с неэкспортированными полями - использовать пакет unsafe
(см. Пример здесь: Доступ к неэкспортированным полям в golang / рефлексе? ), но как его имя говорит: это небезопасно , и вы должны держаться от него подальше, насколько это возможно. Программы, созданные с использованием unsafe
, не гарантируют, что они продолжат работать с более новыми выпусками Go или будут вести себя одинаково на всех платформах.
В общем случае единственный и правильный способ поддержки клонирования в Go - это если сам пакет поддерживает такие операции.
Примечание № 1:
Это не означает, что в некоторых конкретных случаях вы не можете «имитировать» клонирование, создавая новое значение и создавая его состояние вручную. Например, вы можете клонировать map
, создав новую карту, итерируя по парам ключ-значение оригинала и установив их на новой карте.
Примечание № 2:
Обратите внимание, что вы можете делать «точные» копии структур, имеющих неэкспортированные поля, просто присваивая их другой переменной структуры (того же типа), которая также будет правильно копировать неэкспортированные поля.
Как в этом примере:
type person struct {
Name string
age *int
}
age := 22
p := &person{"Bob", &age}
fmt.Println(p)
p2 := new(person)
*p2 = *p
fmt.Println(p2)
Что будет выводиться (попробуйте на Go Playground ):
&{Bob 0x414020}
&{Bob 0x414020}
Что мы можем обобщить, используя reflect
, не полагаясь на конкретный тип:
type person struct {
Name string
age *int
}
age := 22
p := &person{"Bob", &age}
fmt.Println(p)
v := reflect.ValueOf(p).Elem()
vp2 := reflect.New(v.Type())
vp2.Elem().Set(v)
fmt.Println(vp2)
Попробуйте это на Go Playground .
Но то, что мы не можем сделать , это изменить неэкспортированное поле person.age
, чтобы оно указывало на что-то еще. Без помощи объявленного пакета это может быть только nil
или то же значение указателя (указывающее на объект как исходное поле).
См. Также: Более быстрый способ глубокой копии объектов в Голанге