将类型struct A转换为B

问题描述 投票:0回答:3

我想将结构A转换为B,但没有找到解决此问题的简便方法

   type Bob struct {
      Name string 
      Age int 
   }

   type Mark struct {
      Name string 
      Age int 
      HairColor string 
   }

任何想法?我不想为所有属性,例如

编写assign语句
Mark{
Name:bob.Name, 
Age: bob.Age,
}

因为如果结构A和B具有很多类似20的属性,这种方法将非常繁琐

解决方案还应该处理深度嵌套的结构

编辑:有时两个结构的底层结构都不相同,例如A具有更多的属性,例如B,反之亦然

go
3个回答
1
投票

在Go中实现此目标的一般的底层方法是使用反射。您可以查找字段的名称并适当设置值。但是,我建议使用诸如https://github.com/jinzhu/copier之类的库进行深层复制。否则,您会发现它的指针和切片等不同类型变得非常毛茸茸。

您可以简单地做:copier.Copy(&mark, &bob)(显然,mark和bob是Mark和Bob结构的实例)。


3
投票

因为MarkBob具有相同的基础类型,所以conversion可用于在两种类型之间进行转换。这是将Bob转换为Mark的方法:

b := Bob{Name: "Bob", Age: 22}
m := Mark(b)

Run it on the playground

编辑:OP更改了问题。更新后的答案如下。

使用反射包将匹配字段的子集从一个结构复制到另一个结构:

// copyCommonFields copies the common fields from the struct
// pointed to srcp to the struct pointed to by destp.
func copyCommonFields(destp, srcp interface{}) {
    destv := reflect.ValueOf(destp).Elem()
    srcv := reflect.ValueOf(srcp).Elem()

    destt := destv.Type()
    for i := 0; i < destt.NumField(); i++ {
        sf := destt.Field(i)
        v := srcv.FieldByName(sf.Name)
        if !v.IsValid() || !v.Type().AssignableTo(sf.Type) {
            continue
        }
        destv.Field(i).Set(v)
    }
}

像这样使用它:

b := Bob{Name: "Bob", Age: 22, ShoeSize: 9}
var m Mark
copyCommonFields(&m, &b)

Run it on the playground


0
投票

另一种可能性是将公共字段放在单独的结构中,并将其嵌入其他结构中:

type Person struct {
    Name string
    Age  int
}

type Bob struct {
    Person
}

type Mark struct {
    Person
    HairColor string
}

然后您可以使用以下方法创建Mark对象:>

Mark{
    Person: bob.Person,
    // other initializations
}
© www.soinside.com 2019 - 2024. All rights reserved.