2017-07-22 4 views
0

Ich habe folgende structs ...Merging zwei ähnliche Strukturen verschiedenen Typen

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"` 
} 

Und ...

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"` 
} 

Ich brauche im Grunde zwischen den beiden Strukturtypen zu konvertieren, ich habe versuchte, mergo zu verwenden, aber das kann nur Strukturen zusammenführen, die einander zugeordnet werden können. Die einzige Lösung, die ich bisher gefunden habe, besteht darin, durch jede Struktur zu iterieren, die ID zu konvertieren, sie neu zuzuweisen und ihren Typ zwischen string und bson.ObjectId zu konvertieren. Dann durch jedes Kartenfeld iterieren und dasselbe machen. Was sich wie eine ineffiziente Lösung anfühlt.

Ich versuche also, Reflexion zu verwenden, um bei der Konvertierung zwischen den beiden IDs allgemeiner zu sein. Aber ich kann nicht herausfinden, wie ich alle anderen Felder, die automatisch übereinstimmen, effektiv zusammenführen kann, so dass ich mich nur um die Konvertierung zwischen den ID-Typen kümmern kann.

Hier ist der Code, den ich bisher haben ...

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 
} 

Ich bin nicht nur die Felder manuell neu zuweisen, weil ich hoffe, Karten auf den structs Felder zu erkennen und diese rekursiv durchführen Funktion auf ihnen, aber die Felder werden nicht auf eingebetteten Strukturen identisch sein.

Hoffe das macht Sinn!

+2

[ 'bson.ObjectId'] (http://godoc.org/labix.org/v2/mgo/bson#ObjectId) ist definiert als 'typeObjectId string', damit Sie anstelle von reflection den Typ casting (zu' string') verwenden können. Zur Klarstellung, sind beide Strukturen * gleiche Felder mit unterschiedlichem Typ *, wie in der Frage gezeigt, oder kann es verschiedene Felder haben? Wenn ersteres wahr ist, denke ich, dass Sie die erste Struktur zu JSON marshalieren können und dann die JSON zu der zweiten Struktur unmarshalen. – putu

Antwort

1

Ich denke, dass es wahrscheinlich besser ist, einen eigenen Konverter zu schreiben, weil Sie immer einige Fälle haben werden, die nicht von vorhandenen libs \ tools dafür abgedeckt werden.

Meine anfängliche Implementierung wäre es so etwas wie dieses: basic impl of structs merger

+0

Das sieht sehr schlau aus, ich habe es gegen unser aktuelles Problem versucht, und bin ich der Meinung, dass dies nur für root-Felder gilt? Wenn dieser Code beispielsweise ein Feld erreicht, bei dem es sich um eine Karte handelt, werden die zugrunde liegende Karte und die ID-Felder innerhalb dieser Karte nicht konvertiert. Also muss ich in der Lage sein, dies rekursiv über jedes Feld, das eine Karte ist, zu laufen? –

+0

Für Felder, die unterschiedliche Typen haben, müssen Sie einen eigenen 'Übersetzer' angeben. Wenn Sie das Feld vom Typ 'map [MyID] MyStruct' in' map [int] OtherStruct' konvertieren möchten, sollten Sie 'Bind' für die Felder definieren, in denen' Translator' konvertiert werden soll. Sehen Sie sich das erweiterte Beispiel mit dem Kartenfeld hier an: https://play.golang.org/p/crYjG2qGFq –