合并两个不同类型的相似结构体

huangapple go评论64阅读模式
英文:

Merging two similar structs of different types

问题

我有以下的结构体...

type Menu struct {
    Id          string     `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
    Name        string     `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
    Description string     `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
    Mixers      []*Mixer   `protobuf:"bytes,4,rep,name=mixers" json:"mixers,omitempty"`
    Sections    []*Section `protobuf:"bytes,5,rep,name=sections" json:"sections,omitempty"`
}

还有...

type Menu struct {
    ID          bson.ObjectId `json:"id" bson:"_id"`
    Name        string        `json:"name" bson:"name"`
    Description string        `json:"description" bson:"description"`
    Mixers      []Mixer       `json:"mixers" bson:"mixers"`
    Sections    []Section     `json:"sections" bson:"sections"`
}

我基本上需要在这两种结构体类型之间进行转换,我尝试使用 mergo,但它只能合并可相互赋值的结构体。到目前为止,我唯一的解决方案是遍历每个结构体,通过重新赋值来转换 ID,并在 string 和 bson.ObjectId 之间转换其类型。然后遍历每个映射字段并执行相同的操作。这种方法感觉效率低下。

因此,我尝试使用反射来更通用地在两个 ID 之间进行转换。但我无法弄清楚如何有效地合并所有其他匹配的字段,以便我只需要担心 ID 类型之间的转换。

以下是我目前的代码...

package main

import (
    "fmt"
    "reflect"

    "gopkg.in/mgo.v2/bson"
)

type Sub struct {
    Id bson.ObjectId
}

type PbSub struct {
    Id string
}

type PbMenu struct {
    Id   string
    Subs []PbSub
}

type Menu struct {
    Id   bson.ObjectId
    Subs []Sub
}

func main() {
    pbMenus := []*PbMenu{
        &PbMenu{"1", []PbSub{PbSub{"1"}}},
        &PbMenu{"2", []PbSub{PbSub{"1"}}},
        &PbMenu{"3", []PbSub{PbSub{"1"}}},
    }

    newMenus := Serialise(pbMenus)
    fmt.Println(newMenus)
}

type union struct {
    PbMenu
    Menu
}

func Serialise(menus []*PbMenu) []Menu {
    newMenus := []Menu{}
    for _, v := range menus {
        m := reflect.TypeOf(*v)
        fmt.Println(m)
        length := m.NumField()
        for i := 0; i < length; i++ {
            field := reflect.TypeOf(v).Field(i)
            fmt.Println(field.Type.Kind())
            if field.Type.Kind() == reflect.Map {
                fmt.Println("is map")
            }
            if field.Name == "Id" && field.Type.String() == "string" {

                // Convert ID type
                id := bson.ObjectId(v.Id)
                var dst Menu
                dst.Id = id

                // Need to merge other matching struct fields

                newMenus = append(newMenus, dst)
            }
        }
    }
    return newMenus
}

我不能手动重新分配字段,因为我希望检测到结构体字段中的映射,并对它们递归执行此函数,但嵌入结构体上的字段将不相同。

希望这样说得清楚!

英文:

I have the following structs...

type Menu struct {
	Id          string     `protobuf:&quot;bytes,1,opt,name=id&quot; json:&quot;id,omitempty&quot;`
	Name        string     `protobuf:&quot;bytes,2,opt,name=name&quot; json:&quot;name,omitempty&quot;`
	Description string     `protobuf:&quot;bytes,3,opt,name=description&quot; json:&quot;description,omitempty&quot;`
	Mixers      []*Mixer   `protobuf:&quot;bytes,4,rep,name=mixers&quot; json:&quot;mixers,omitempty&quot;`
	Sections    []*Section `protobuf:&quot;bytes,5,rep,name=sections&quot; json:&quot;sections,omitempty&quot;`
}

And...

type Menu struct {
	ID          bson.ObjectId `json:&quot;id&quot; bson:&quot;_id&quot;`
	Name        string        `json:&quot;name&quot; bson:&quot;name&quot;`
	Description string        `json:&quot;description&quot; bson:&quot;description&quot;`
	Mixers      []Mixer       `json:&quot;mixers&quot; bson:&quot;mixers&quot;`
	Sections    []Section     `json:&quot;sections&quot; bson:&quot;sections&quot;`
}

I basically need to convert between the two struct types, I've attempted to use mergo, but that can only merge structs that are assignable to one another. The only solution I have so far is iterating through each struct, converting the ID by re-assigning it and converting its type between string and bson.ObjectId. Then iterating through each map field and doing the same. Which feels like an inefficient solution.

So I'm attempting to use reflection to be more generic in converting between the two ID's. But I can't figure out how I can effectively merge all of the other fields that do match automatically, so I can just worry about converting between the ID types.

Here's the code I have so far...

package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;

	&quot;gopkg.in/mgo.v2/bson&quot;
)

type Sub struct {
	Id bson.ObjectId
}

type PbSub struct {
	Id string
}

type PbMenu struct {
	Id   string
	Subs []PbSub
}

type Menu struct {
	Id   bson.ObjectId
	Subs []Sub
}

func main() {
	pbMenus := []*PbMenu{
		&amp;PbMenu{&quot;1&quot;, []PbSub{PbSub{&quot;1&quot;}}},
		&amp;PbMenu{&quot;2&quot;, []PbSub{PbSub{&quot;1&quot;}}},
		&amp;PbMenu{&quot;3&quot;, []PbSub{PbSub{&quot;1&quot;}}},
	}

	newMenus := Serialise(pbMenus)
	fmt.Println(newMenus)
}

type union struct {
	PbMenu
	Menu
}

func Serialise(menus []*PbMenu) []Menu {
	newMenus := []Menu{}
	for _, v := range menus {
		m := reflect.TypeOf(*v)
		fmt.Println(m)
		length := m.NumField()
		for i := 0; i &lt; length; i++ {
			field := reflect.TypeOf(v).Field(i)
			fmt.Println(field.Type.Kind())
			if field.Type.Kind() == reflect.Map {
				fmt.Println(&quot;is map&quot;)
			}
			if field.Name == &quot;Id&quot; &amp;&amp; field.Type.String() == &quot;string&quot; {

				// Convert ID type
				id := bson.ObjectId(v.Id)
				var dst Menu
				dst.Id = id

				// Need to merge other matching struct fields

				newMenus = append(newMenus, dst)
			}
		}
	}
	return newMenus
}

I'm can't just manually re-assign the fields because I'm hoping to detect maps on the structs fields and recursively perform this function on them, but the fields won't be the same on embedded structs.

Hope this makes sense!

答案1

得分: 1

我认为最好自己编写转换器,因为现有的库/工具可能无法覆盖所有情况。

我初步的实现方式可能是这样的:基本的结构合并实现

英文:

I think that it is probably better to write your own converter, because you will always have some cases that are not covered by existing libs\tools for that.

My initial implementation of it would be something like this: basic impl of structs merger

huangapple
  • 本文由 发表于 2017年7月22日 20:47:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/45254738.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定