how to merge different struct to one struct

1,006 views
Skip to first unread message

Lee Rick

unread,
Aug 23, 2019, 11:25:27 PM8/23/19
to golang-nuts
i want to do 
type A struct{ Name string}
type B struct{Age int}
type C struct{Address string}

a, b, c := A{}, B{},C{}
have a function
d1 := merge(a,b)  //d1 like struct{Name string, Age int}
d2 := merge(a,c)  //d2 like struct{Name string, Address string}
d3 := merge(b,c) //d3 like struct{Age int, Address string}


how to realize merge function? anyone can give me a demo

burak serdar

unread,
Aug 23, 2019, 11:43:32 PM8/23/19
to Lee Rick, golang-nuts
On Fri, Aug 23, 2019 at 9:25 PM Lee Rick <blade...@gmail.com> wrote:
>
> i want to do
> type A struct{ Name string}
> type B struct{Age int}
> type C struct{Address string}
>
> a, b, c := A{}, B{},C{}
> have a function
> d1 := merge(a,b) //d1 like struct{Name string, Age int}
> d2 := merge(a,c) //d2 like struct{Name string, Address string}
> d3 := merge(b,c) //d3 like struct{Age int, Address string}

You cannot have a function that merges two structs and returns a new
one, but you can have structs that are compositions of other structs.

type AB struct {
A
B
}

Struct AB is a struct containing both A and B. You can access the
members of A and B as though they're members of AB.

ab:=AB{}
ab.Name="a"
ab.Age=1

This is also valid:

ab.A.Name="a"
ab.B.Age=1

Initialization has to be explicit though:

ab:=AB{A:A{Name:"name"}, B:B{Age:1}}




>
>
> how to realize merge function? anyone can give me a demo
>
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/9d0f4159-146b-4d5b-91c0-8846445a84d4%40googlegroups.com.

Lee Rick

unread,
Aug 24, 2019, 1:11:01 AM8/24/19
to golang-nuts
it's not my need, hope other methods

在 2019年8月24日星期六 UTC+8上午11:43:32,burak serdar写道:
> To unsubscribe from this group and stop receiving emails from it, send an email to golan...@googlegroups.com.

Kurtis Rader

unread,
Aug 24, 2019, 1:25:01 AM8/24/19
to Lee Rick, golang-nuts
On Fri, Aug 23, 2019 at 10:11 PM Lee Rick <blade...@gmail.com> wrote:
it's not my need, hope other methods

Then you need to explain why that answer is not satisfactory and otherwise better explain your requirements. In your hypothetical example the objects such as `d1` would not be usable except via reflection (assuming that approach was even viable). What exactly would be the point? If you need a data structure that can be composed at run time there are many options. Why does it need to be a Go struct?

--
Kurtis Rader
Caretaker of the exceptional canines Junior and Hank

burak serdar

unread,
Aug 24, 2019, 1:25:24 AM8/24/19
to Lee Rick, golang-nuts
On Fri, Aug 23, 2019 at 11:11 PM Lee Rick <blade...@gmail.com> wrote:
>
> it's not my need, hope other methods

What is your need? What are the types of the variables d1, d2, d3 in
your example?
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/f7e61c2d-1aef-4160-b525-7d9c2488f9e1%40googlegroups.com.

Jan Mercl

unread,
Aug 24, 2019, 1:29:03 AM8/24/19
to Lee Rick, golang-nuts
Is this the XY problem? What is the task/goal?

Lee Rick

unread,
Aug 24, 2019, 3:39:27 AM8/24/19
to golang-nuts
think that there are two struct, they have different fields, hope that there has a function merge(a,b interface{}) interface{}, input param are any two struct, they may have same-type, or have different-type. output param is a struct that composed the two input struct, example type A sturct{Name string}, type B struct{Age int}, a,b :=A{"xxx"},B{10} called c:= merge(a,b), c is interface{}, and 

v, _ := query.Values(opt)
fmt.Print(v.Encode()) // will output: "name=xxx&age=10"


在 2019年8月24日星期六 UTC+8下午1:25:01,Kurtis Rader写道:

Lee Rick

unread,
Aug 24, 2019, 3:40:24 AM8/24/19
to golang-nuts
think that there are two struct, they have different fields, hope that there has a function merge(a,b interface{}) interface{}, input param are any two struct, they may have same-type, or have different-type. output param is a struct that composed the two input struct, example type A sturct{Name string}, type B struct{Age int}, a,b :=A{"xxx"},B{10} called c:= merge(a,b), c is interface{}, and 

v, _ := query.Values(opt)
fmt.Print(v.Encode()) // will output: "name=xxx&age=10"

在 2019年8月24日星期六 UTC+8下午1:29:03,Jan Mercl写道:

Lee Rick

unread,
Aug 24, 2019, 3:41:06 AM8/24/19
to golang-nuts
think that there are two struct, they have different fields, hope that there has a function merge(a,b interface{}) interface{}, input param are any two struct, they may have same-type, or have different-type. output param is a struct that composed the two input struct, example type A sturct{Name string}, type B struct{Age int}, a,b :=A{"xxx"},B{10} called c:= merge(a,b), c is interface{}, and 

v, _ := query.Values(opt)
fmt.Print(v.Encode()) // will output: "name=xxx&age=10"

在 2019年8月24日星期六 UTC+8下午1:25:24,burak serdar写道:

Jacques Supcik

unread,
Aug 24, 2019, 6:12:40 AM8/24/19
to golang-nuts
As suggested by Kurtis Rader, I would use "reflection" for this.

Here is a simple example (not fully tested, probably not safe, not production ready... so just for demonstration purpose) :

Lee Rick

unread,
Aug 24, 2019, 7:48:43 AM8/24/19
to golang-nuts
i read your code, and try to write my code,

package main

import (
"fmt"
"reflect"
)

type A struct{ Name string }
type B struct{ Age int }
type C struct{ Address string }

func Merge(a interface{}, b interface{})( d interface{}) {
aType := reflect.TypeOf(a)
if aType.Kind() != reflect.Struct {
panic("a is not a struct")
}

bType := reflect.TypeOf(b)
if bType.Kind() != reflect.Struct {
panic("b is not a struct")
}

var fields []reflect.StructField
for i:=0 ; i< aType.NumField(); i++{
  fields =append(fields, aType.Field(i))
}
for i:=0 ; i< bType.NumField(); i++{
  fields =append(fields, bType.Field(i))
}

dType := reflect.StructOf(fields)
dVal := reflect.Indirect(reflect.New(dType))


aVal := reflect.ValueOf(a)
bVal := reflect.ValueOf(b)

for i := 0; i < aType.NumField(); i++ {
dVal.FieldByName(aType.Field(i).Name).Set(aVal.Field(i))
}
for i := 0; i < bType.NumField(); i++ {
dVal.FieldByName(bType.Field(i).Name).Set(bVal.Field(i))
}
d = dVal.Interface()
return 
}

func main() {
a, b, c := A{"John"}, B{42}, C{"World"}

d1 := Merge(a, b)
d2 := Merge(a, c)
d3 := Merge(b, c)

fmt.Printf("%#v\n",d1)
fmt.Printf("%#v\n",d2)
fmt.Printf("%#v\n",d3)
}

output, it's my want

struct { Name string; Age int }{Name:"John", Age:42}
struct { Name string; Address string }{Name:"John", Address:"World"}
struct { Age int; Address string }{Age:42, Address:"World"}


thanks all people

在 2019年8月24日星期六 UTC+8下午6:12:40,Jacques Supcik写道:

Jacques Supcik

unread,
Aug 24, 2019, 9:13:49 AM8/24/19
to Lee Rick, golang-nuts
I'm glad I could help.

Cheers,

-- Jacques

jake...@gmail.com

unread,
Aug 24, 2019, 12:45:23 PM8/24/19
to golang-nuts
On Saturday, August 24, 2019 at 3:39:27 AM UTC-4, Lee Rick wrote:
think that there are two struct, they have different fields, hope that there has a function merge(a,b interface{}) interface{}, input param are any two struct, they may have same-type, or have different-type. output param is a struct that composed the two input struct, example type A sturct{Name string}, type B struct{Age int}, a,b :=A{"xxx"},B{10} called c:= merge(a,b), c is interface{}, and 

v, _ := query.Values(opt)
fmt.Print(v.Encode()) // will output: "name=xxx&age=10"


This still sounds very much like the XY Problem. If you goal is really to combine two structs for the purpose of encoding them using the net/url Value type, then the using reflection to create a new type is probably overly complicated and inefficient. A much simpler, and more idiomatic, way to achieve the same result would be to merege the url.Value's created from two calls to query.Values(). Something like:
package main

import "fmt"
import "github.com/google/go-querystring/query"


type A
struct{ Name string }

type B
struct{ Age int }


func main
() {
    a
:= A{Name: "foo"}
    b
:= B{Age: 7}

    va
, _ := query.Values(a)
    vb
, _ := query.Values(b)

   
for k, vslice := range vb {
        fmt
.Println("Key: ", k, "Value: ", vslice)
       
for _, v := range vslice {
            va
.Add(k, v)
       
}
   
}
    fmt
.Print(va.Encode())
}
This is just an example, and the combining logic could be pulled out into a general function.

If on the other hand, you have a situation where you are passing an interface{} to code over which you have no control, then reflection may be the best way. However, you should probably refernce the specific code (over which you have no control) so others could help find a possible solution based on you actual problem.
Reply all
Reply to author
Forward
0 new messages