Скопируйте одну структуру в другую, где структуры имеют одинаковых членов и разные типы

У меня есть две struct имеющие одинаковые члены, я хочу скопировать одну структуру в другую, см. Псевдокод ниже:

type Common struct {
    Gender int
    From   string
    To     string
}

type Foo struct {
    Id    string
    Name  string
    Extra Common
}

type Bar struct {
    Id    string
    Name  string
    Extra Common
}

Тогда у меня есть foo структуры Foo и bar структуры Bar Есть ли способ скопировать bar из foo?

Ответ 1

Используйте конверсию. В следующем коде используется преобразование для копирования значения типа Foo в значение типа Bar:

foo := Foo{Id: "123", Name: "Joe"}
bar := Bar(foo)

Пример детской площадки

преобразование работает только тогда, когда базовые типы идентичны, за исключением тегов структуры.

Ответ 2

Если вы хотите скопировать или клонировать другую структуру, я бы предложил использовать deepcopier

Это обеспечивает хорошие функции, такие как пропуск, пользовательское сопоставление и форсирование. ниже приведен пример из github:

Установка:

go get -u github.com/ulule/deepcopier

Пример:

package main

import (
    "fmt"

    "github.com/ulule/deepcopier"
)

// Model
type User struct {
    // Basic string field
    Name  string
    // Deepcopier supports https://golang.org/pkg/database/sql/driver/#Valuer
    Email sql.NullString
}

func (u *User) MethodThatTakesContext(ctx map[string]interface{}) string {
    // do whatever you want
    return "hello from this method"
}

// Resource
type UserResource struct {
    //copy from field "Name"
    DisplayName            string 'deepcopier:"field:Name"'
    //this will be skipped in copy 
    SkipMe                 string 'deepcopier:"skip"'
    //this should call method named MethodThatTakesContext 
    MethodThatTakesContext string 'deepcopier:"context"'
    Email                  string 'deepcopier:"force"'

}

func main() {
    user := &User{
        Name: "gilles",
        Email: sql.NullString{
            Valid: true,
            String: "[email protected]",
        },
    }

    resource := &UserResource{}

    deepcopier.Copy(user).To(resource)
    //copied from User Name field
    fmt.Println(resource.DisplayName)//output: gilles
    fmt.Println(resource.Email) //output: [email protected]
    fmt.Println(resource.MethodThatTakesContext) //output: hello from this method
}

Кроме того, другим способом добиться этого можно путем кодирования исходного объекта в JSON, а затем декодирования его обратно в целевой объект.

Ответ 3

https://github.com/jinzhu/copier (тот же автор gorm) также довольно хороший, у меня есть вложенные структуры, и все, что я делаю, это:

copier.Copy(&employees, &user)

работает отлично

Ответ 4

Если вы хотите скопировать или клонировать другую структуру, я бы предложил использовать deepcopier

Он предоставляет хорошие функции, такие как пропуск, пользовательское сопоставление и форсирование.

Вы можете добиться вложенного копирования структуры следующим образом. Установить:

go get -u github.com/ulule/deepcopier

Пример:

 package main

    import (
        "fmt"
        "strconv"

        "github.com/ulule/deepcopier"
    )

    //FieldStruct -  Field Struct
    type FieldStruct struct {
        Name string 'deepcopier:"field:TargetName"'
        Type string 'deepcopier:"field:TargetType"'
    }

    //SourceStruct - Source Struct
    type SourceStruct struct {
        Name        string   'deepcopier:"field:TargetName"'
        Age         int      'deepcopier:"field:TargetAge"'
        StringArray []string 'deepcopier:"field:TargetStringArray"'
        StringToInt string   'deepcopier:"context"'
        Field       FieldStruct
        Fields      []FieldStruct
    }

    //TargetFieldStruct -  Field Struct
    type TargetFieldStruct struct {
        TargetName string
        TargetType string
    }

    //TargetStruct - Target Struct
    type TargetStruct struct {
        TargetName        string
        TargetAge         int
        TargetStringArray []string
        TargetInt         int
        TargetField       TargetFieldStruct
        TargetFields      []TargetFieldStruct
    }

    //write methods

    //TargetInt - StringToInt
    func (s *SourceStruct) TargetInt() int {
        i, _ := strconv.Atoi(s.StringToInt)
        return i
    }

    func main() {
        s := &SourceStruct{
            Name:        "Name",
            Age:         12,
            StringArray: []string{"1", "2"},
            StringToInt: "123",
            Field: FieldStruct{
                Name: "Field",
                Type: "String",
            },
            Fields: []FieldStruct{
                FieldStruct{
                    Name: "Field1",
                    Type: "String1",
                },
                FieldStruct{
                    Name: "Field2",
                    Type: "String2",
                },
            },
        }

        t := &TargetStruct{}

        //coping data into inner struct
        deepcopier.Copy(&t.TargetField).From(&s.Field)

        // copied array of Struct
        for i := range s.Fields {
            // init a struct
            t.TargetFields = append(t.TargetFields, TargetFieldStruct{})
            // coping the data
            deepcopier.Copy(&t.TargetFields[i]).From(&s.Fields[i])
        }
        //Top level copy
        deepcopier.Copy(t).From(s)

        fmt.Println(t)
    }

Выход: & {Имя 12 [12] 123 {Строка поля} [{Строка1 Строка1} {Строка2 Строка2}]}