Reputation: 451
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
Upvotes: 3
Views: 4199
Reputation: 502
If first fields are the same and you aren't squeamish about using unsafe, then here's the fastest one line solution:
https://play.golang.org/p/gqlq-vLsLXE
Upvotes: 0
Reputation: 6749
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
}
Upvotes: 2
Reputation: 120960
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)
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)
Upvotes: 3
Reputation: 12035
The general, low-level way to achieve this in Go is by using reflection. You can look up the names of the fields and set the values appropriately. However I would recommend using a library, such as https://github.com/jinzhu/copier for deep copying. Otherwise you'll find it gets quite hairy with different types such as pointers and slices.
You can simply do: copier.Copy(&mark, &bob)
(where mark and bob are instances of Mark and Bob structs, obviously).
Upvotes: 1