2017-08-23 1 views
0

Ich möchte eine Methode erstellen, die eine Struktur als interface{} nimmt und true zurückgibt, wenn eines der Felder der bereitgestellten Struktur NULL sind.Rekursiv durch verschachtelte Strukturen gehen

Hier ist, was ich im Moment haben:

// ContainsNil returns true if any fields within the supplied structure are nil. 
// 
// If the supplied object is not a struct, the method will panic. 
// Nested structs are inspected recursively. 
// Maps and slices are not inspected deeply. This may change. 
func ContainsNil(obj interface{}) bool { 
    if obj == nil { 
     return true 
    } 
    s := reflect.Indirect(reflect.ValueOf(obj)) 
    for i := 0; i < s.NumField(); i++ { 
     f := s.Type().Field(i) 
     field := s.Field(i) 
     if fieldIsExported(f) { // Exported-check must be evaluated first to avoid panic. 
      if field.Kind() == reflect.Struct { 
       if ContainsNil(field.Addr()) { 
        return true 
       } 
      } else { 
       if field.IsNil() { 
        return true 
       } 
       if field.Interface() == nil { 
        return true 
       } 
      } 
     } 
    } 
    return false 
} 

func fieldIsExported(field reflect.StructField) bool { 
    log.Println(field.Name) 
    return field.Name[0] >= 65 == true && field.Name[0] <= 90 == true 
} 

Und eine versagende Test:

func Test_ContainsNil_NilNestedValue_ReturnsTrue(t *testing.T) { 
    someNestedStruct := &c.SomeNestedStruct{ 
     SomeStruct: c.SomeStruct{ 
      SomeString: nil, 
     }, 
    } 
    result := util.ContainsNil(someNestedStruct) 
    assert.True(t, result) 
} 

Der Testcode ausführt, ohne in Panik zu geraten, aber nicht, weil die Methode false zurückgibt, anstatt true.

Das Problem, das ich habe, ist, dass ich nicht herausfinden kann, wie die verschachtelte Struktur zurück in den rekursiven Aufruf an ContainsNil übergeben.

Wenn der rekursive Aufruf für die verschachtelte Struktur erfolgt, gibt die fieldIsExported-Methode false zurück, weil sie nicht den Wert empfängt, den ich erwarten würde, dass sie empfangen wird.

Ich erwarte fieldIsExported, "SomeStruct" bei seinem ersten Aufruf zu empfangen, und "SomeString" beim zweiten (rekursiven) Aufruf zu erhalten. Der erste Anruf verläuft wie erwartet, aber beim zweiten Anruf erhält fieldIsExported "typ", wenn ich erwarte, dass es "SomeString" empfängt.

Ich habe eine Menge Forschung über die Verwendung von reflects auf Strukturen gemacht, aber ich war noch nicht in der Lage, meinen Kopf dazu zu bringen. Ideen?

Referenzen:

Antwort

1

googeln Sie überprüfen, ob das aktuelle Feld eine Struktur Wert, ist aber nie erklären für den Fall, dass n es ist ein reflect.Ptr zu einer Struktur oder etwas anderes, so dass Ihre Funktion nie für diesen Fall recurses. Hier ist deine Funktion mit dem fehlenden Stück.

https://play.golang.org/p/FdLxeee9UU

// ContainsNil returns true if any fields within the supplied structure are nil. 
// 
// If the supplied object is not a struct, the method will panic. 
// Nested structs are inspected recursively. 
// Maps and slices are not inspected deeply. This may change. 
func ContainsNil(obj interface{}) bool { 
    if obj == nil { 
     return true 
    } 
    s := reflect.Indirect(reflect.ValueOf(obj)) 
    for i := 0; i < s.NumField(); i++ { 
     f := s.Type().Field(i) 
     field := s.Field(i) 
     if fieldIsExported(f) { // Exported-check must be evaluated first to avoid panic. 
      if field.Kind() == reflect.Ptr { // case when it's a pointer or struct pointer 
       if field.IsNil() { 
        return true 
       } 
       if ContainsNil(field.Interface()) { 
        return true 
       } 
      } 
      if field.Kind() == reflect.Struct { 
       if ContainsNil(field.Addr()) { 
        return true 
       } 
      } else { 
       if field.IsNil() { 
        return true 
       } 
       if field.Interface() == nil { 
        return true 
       } 
      } 
     } 
    } 
    return false 
} 
+0

Dies macht durchaus Sinn. Vielen Dank für die Hilfe! – Joe

Verwandte Themen