2017-08-23 16 views
0

構造体をinterface{}として取得するメソッドを作成し、指定された構造体のフィールドがnilの場合はtrueを返します。ここでネストされた構造体を再帰的に参照します

は私が現時点で持っているものです。

// 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 
} 

し、障害のテスト:

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

テストコードは、慌てずに実行されますが、この方法はfalseではなくtrueを返すために失敗します。

問題は、ContainsNilへの再帰呼び出しにネストされた構造体を正しく渡す方法がわかりません。

ネストされた構造体に対して再帰呼び出しが行われると、fieldIsExportedメソッドは、受信すると予想される値を受信して​​いないため、falseを返します。

fieldIsExportedは、最初の呼び出しで "SomeStruct"を受け取り、2番目(再帰的)呼び出しで "SomeString"を受け取ると期待しています。最初の呼び出しは期待どおりに行われますが、2番目の呼び出しではfieldIsExportedは "typString"を受け取ると予想されますが、 "typ"を受け取ります。

私は、構造体に反映使用についての研究の束をやったが、私はまだこのまわりで私の頭を取得することができていません。アイデア?

参考文献:

答えて

1

をグーグルでの現在のフィールドが構造体であるかどうかをチェックしていますが、アカウントはありませんケースwheの場合nそれは構造体または何か他のものへのreflect.Ptrなので、あなたの関数は決してそのケースに対して再帰しません。ここにあなたの機能があります。

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

これは完璧な意味があります。助けてくれてありがとう! – Joe

関連する問題