Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert a type struct A to B

Tags:

go

I want to convert Struct A to B but I didn’t found a simple and good approach for this problem

   type Bob struct {
      Name string 
      Age int 
   }

   type Mark struct {
      Name string 
      Age int 
      HairColor string 
   }

any ideas? I don’t want to write a assign statement for all properties like

Mark{
Name:bob.Name, 
Age: bob.Age,
}

Because this approach get's very tedious if a Struct A and B have a lot of properties like 20

The solution should also handle deeply nested structs

Edit: sometimes the underlying structure isn’t equal of both structs like A has more properties like B or vice versa

like image 940
Donutloop Avatar asked Oct 17 '25 16:10

Donutloop


2 Answers

Because Mark and Bob have the same underlying type, a conversion can be used to to convert between the two types. Here's how to convert a Bob to a Mark:

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

Run it on the playground.

Edit: OP changed the question. Updated answer follows.

Use the reflect package to copy the subset of matching fields from one struct to the other:

// 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)
    }
}

Use it like this:

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

Run it on the playground.

Another possibility is to put the common fields in a separate struct and embed that in the other structs:

type Person struct {
    Name string
    Age  int
}

type Bob struct {
    Person
}

type Mark struct {
    Person
    HairColor string
}

Then you can create a Mark object with

Mark{
    Person: bob.Person,
    // other initializations
}
like image 21
Andy Schweig Avatar answered Oct 20 '25 06:10

Andy Schweig



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!