将一个结构体复制到另一个结构体中,这两个结构体具有相同的成员但类型不同。

71

我有两个struct,它们具有相同的成员,我希望将一个struct复制到另一个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,是否有办法从 foo 复制 bar

5个回答

100

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

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

操场示例

只有在底层类型相同但结构标签不同的情况下,转换才能生效。


15
好的。显然,只有当两个结构体完全具有相同的结构时,此方法才有效。 - Tigraine
2
...但是将同一结构类型复制并不起作用 - John White
@CeriseLimón 要将一个结构体复制到另一个实例中,转换实际上并不会做任何事情,而只是赋值才能正确地完成它。 - John White
@JohnWhite 这个问题是关于复制到不同类型,而不是相同类型。当类型相同时,赋值就足够了(对于所有类型,包括结构体类型都是如此)。与您的第一条评论相反,不必要的转换确实可以工作(示例)。 - Charlie Tumahai

26

https://github.com/jinzhu/copier(gorm的同一位作者)也是一个很不错的工具,我有嵌套结构体,而我所做的一切就是:

copier.Copy(&employees, &user)

非常好用。


7
如果您想将数据结构复制或克隆到另一个结构中,我建议使用 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: "gilles@example.com",
        },
    }

    resource := &UserResource{}

    deepcopier.Copy(user).To(resource)
    //copied from User's Name field
    fmt.Println(resource.DisplayName)//output: gilles
    fmt.Println(resource.Email) //output: gilles@example.com
    fmt.Println(resource.MethodThatTakesContext) //output: hello from this method
}

此外,你还可以通过将源对象编码为JSON,然后将其解码回目标对象来实现此目的。

6

以下是另一种可能的答案

类型公共结构体 { 性别 int 来自 字符串 到 字符串 }

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\n",bar)

2
如果您想复制或克隆到不同的结构体,我建议使用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 [1 2] 123 {字段 字符串} [{字段1 字符串1} {字段2 字符串2}]}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接