2017-12-03 5 views
1

Ich versuche rekursiv über eine Struktur zu reflektieren, die Art der einzelnen Felder auszudrucken. Wo ein Feld ein Stück von Strukturen ist, würde ich gerne identifizieren den Typ im Array gehalten und dann über diesen Typ reflektieren.Golan recurisive Reflexion

Hier ist ein Beispielcode

package main 

import (
    "log" 
    "reflect" 
) 

type child struct { 
    Name *string 
    Age int 
} 

type Parent struct { 
    Name  string 
    Surname *string 
    Children []*child 
    PetNames []string 
} 

func main() { 

    typ := reflect.TypeOf(Parent{}) 
    log.Printf("This is a : %s", typ.Kind()) 

    for i := 0; i < typ.NumField(); i++ { 
     p := typ.Field(i) 
     if !p.Anonymous { 
      switch p.Type.Kind() { 
      case reflect.Ptr: 
       log.Printf("Ptr: %s is a type %s", p.Name, p.Type) 
      case reflect.Slice: 
       log.Printf("Slice: %s is a type %s", p.Name, p.Type) 
       subtyp := p.Type.Elem() 
       if subtyp.Kind() == reflect.Ptr { 
        subtyp = subtyp.Elem() 
       } 
       log.Printf("\tDereferenced Type%s", subtyp) 
      default: 
       log.Printf("Default: %s is a type %s", p.Name, p.Type) 
      } 
     } 
    } 

} 

Die Ausgabe sieht wie folgt aus:

This is a : struct 
Default: Name is a type string 
Ptr: Surname is a type *string 
Slice: Children is a type []*main.child 
    Dereferenced Type main.child 
Slice: PetNames is a type []string 
    Dereferenced Type string 

Wenn ich erkennen, dass ein Feldtyp eine Scheibe Zeiger ist, ich bin in der Lage zu folge dem Typ durch Aufrufen von subtype.Elem().

Der Ausgang ist 'main.child'

Wenn ich dann versuchen, Kind zu reflektieren mit

subSubType := reflect.TypeOf(subtyp) 
log.Printf("%+v", subSubType) 

ich folgendes:

*reflect.rtype 

Wie kann ich die Reflection-API verwenden über die Felder der Child-Struktur iterieren?

+1

Rufen Sie nicht 'reflect.TypeOf (Subtyp)' , 'Subtyp' ist bereits vom Typ' reflect.Type'. – mkopriva

+1

https://play.golang.org/p/Th0uGACjwH das ist nur ein Beispiel, ich mag nicht die Art, wie ich mit den Feldnamen umgehe, aber es wird langsam spät, also wird dich das hoffentlich nach rechts bringen Richtung. – mkopriva

Antwort

1

Hier ist eine Möglichkeit, es zu tun.

func printType(prefix string, t reflect.Type, visited map[reflect.Type]bool) { 

    // Print the name of this type with opening (for description. 
    fmt.Printf("%s (", t) 

    // Traverse elements, adding to description as we go. 
elems: 
    for { 
     switch t.Kind() { 
     case reflect.Ptr: 
      fmt.Print("ptr to ") 
     case reflect.Slice: 
      fmt.Print("slice of ") 
     case reflect.Array: 
      fmt.Printf("array with %d elements of ", t.Len()) 
     default: 
      break elems 
     } 
     t = t.Elem() 
    } 

    // Print the kind of the type and the closing) of the description. 
    // In the case of a struct, we print the names of the fields and recurse. 
    switch t.Kind() { 
    case reflect.Struct: 
     fmt.Printf("struct with %d fields)\n", t.NumField()) 
     if visited[t] { 
      // Don't blow up on recursive type definition. 
      break 
     } 
     visited[t] = true 
     prefix += " " 
     for i := 0; i < t.NumField(); i++ { 
      f := t.Field(i) 
      fmt.Print(prefix, f.Name, " ") 
      printType(prefix, f.Type, visited) 
     } 
    default: 
     fmt.Printf("%s)\n", t.Kind()) 
    } 
} 

func main() { 
    printType("", reflect.TypeOf(Parent{}), make(map[reflect.Type]bool)) 
} 

die Ausgabe für Eltern {} gegeben folgende Typen:

type child struct { 
    Name *string 
    Age int 
} 

type Parent struct { 
    Name  string 
    Surname *string 
    Children []*child 
    PetNames []string 
    Parents [2]*Parent 
    child 
} 

ist:

main.Parent (struct with 6 fields) 
    Name string (string) 
    Surname *string (ptr to string) 
    Children []*main.child (slice of ptr to struct with 2 fields) 
     Name *string (ptr to string) 
     Age int (int) 
    PetNames []string (slice of string) 
    Parents [2]*main.Parent (array with 2 elements of ptr to struct with 6 fields) 
    child main.child (struct with 2 fields) 

playground example

+0

Danke das funktioniert. –

+0

Danke das funktioniert. Wenn ich eine Struktur mit Werten übergeben möchte, ist es möglich, auch die Werte für jedes Feld zu extrahieren? ieparent: = Parent {Name: "Joe", Kinder: [] * Kind {& Kind {Name: "Bobby", Alter: 4,},},} Dann würde die Ausgabe "Name * string (ptr to string)" ausgeben (Bobby) "? –

+0

Der obige Code funktioniert mit Typen wie in der Frage gefragt. Der Code für Werte wird sehr ähnlich sein. Verwenden Sie fmt.Sprintf ("% v", v), um die Werte zu drucken. –