关于开始:将一个结构复制到另一个结构中,该结构具有相同的成员和不同的类型


Copy one struct to another where structs have same members and different types

我有两个具有相同成员的struct,我想将一个结构复制到另一个结构,请参见下面的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
}

然后我有结构foofoo和结构barbar,有什么方法可以从foo复制bar吗?


使用转换来更改类型。以下代码使用转换将类型Foo的值复制到类型Bar的值:

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

游乐场的例子

仅当基础类型相同(结构标记除外)时,转换才有效。


如果您想复制或克隆到其他结构,我建议使用deepcopier

它提供了很好的功能,例如跳过,自定义映射和强制。以下是来自github的示例:

安装:

1
go get -u github.com/ulule/deepcopier

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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's 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,然后将其解码回目标对象来实现。


https://github.com/jinzhu/copier(gorm的同一作者)也很不错,我嵌套了结构,我所做的就是:

copier.Copy(&employees, &user)

效果很好


这是另一个可能的答案

输入Common struct {
性别诠释
从字符串

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type Foo struct {
    Id    string
    Name  string
    Extra Common
}

type Bar struct {
    Id    string
    Name  string
    Extra Common
}
foo:=Foo{
    Id:"123",
    Name:"damitha",
    Extra: struct {
        Gender int
        From   string
        To     string
    }{Gender:1 , From:"xx", To:"yy" },
}
bar:=*(*Bar)(unsafe.Pointer(&foo))
fmt.Printf("%+v\
",bar)


如果您想复制或克隆到其他结构,我建议使用deepcopier

它提供了很好的功能,例如跳过,自定义映射和强制。

您可以按照以下方式实现嵌套的struct复制。
安装:

1
go get -u github.com/ulule/deepcopier

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
 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 [1 2] 123 {字段字符串} [{Field1 String1} {Field2 String2}]}