Как скопировать структуру и разыменовать все указатели - PullRequest
0 голосов
/ 10 мая 2018

Как скопировать структуру Item и все указатели в новую структуру?

type Item struct {
    A    []*ASet     `json:"a,omitempty"`
    B    []*BSet.    `json:"b,omitempty"`
    C    []*CSet.    `json:"c,omitempty"`
}


type ASet struct {
    UID   string     `json:"uid,omitempty"`
    Items []*ItemA `json:"member,omitempty"`
}

type ItemA struct {
    UID  string `json:"uid,omitempty"`
    Portset []*PortSet `json:"portset,omitempty"`
}

type PortSet struct {
    UID   string     `json:"uid,omitempty"`
    Ports []*Port `json:"member,omitempty"`
}

type Port struct {
    UID  string `json:"uid,omitempty"`
    Port int    `json:"port,omitempty"`
}

Я не хочу, чтобы новая структура ссылалась на старую структуру.

1 Ответ

0 голосов
/ 10 мая 2018

То, что вы хотите - это, по сути, глубокая копия, которая не поддерживается стандартной библиотекой.

Ваш выбор:

  • Сделайте копию "вручную", например, создайте новую структуру и скопируйте поля, в которых указатели или фрагменты / карты / каналы / и т. д. должны дублироваться вручную, рекурсивным способом.
    Это проще всего сделать, назначив вашу структуру другой, которая копирует все поля, так что вам, по сути, нужно только лелеять указатели / карты / фрагменты и т. Д. (Но рекурсивно).
  • Использовать внешнюю библиотеку, например, 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)
...