問題內容
上下文:我正在編寫一個通用自動映射器,它采用兩種類型的結構,檢查所述結構的每個字段是否有給定的標簽,然后將值從源結構復制到目標結構,假設它們具有匹配的標簽和類型。每當結構字段是另一個(嵌套)結構時,我希望自動映射器函數執行遞歸調用,自動映射到兔子洞。
問題:我只能傳遞根結構的具體類型。一旦我進入使用反射的通用函數,嘗試提取嵌套的結構類型似乎是不可能的。
雖然我可以傳遞 value.interface() 作為參數,但我仍然需要傳遞類型參數。
這里有一些簡化的代碼來顯示問題。
type Alpha struct { Nested Beta `automap:"nested"` } type Beta struct { Info string `automap:"info"` } type Foo struct { Nested Bar `automap:"nested"` } type Bar struct { Info string `automap:"info"` } func TestAutoMap(t *testing.T) { b := Beta{Info: "Hello from Beta!"} a := Alpha{Nested: b} f, err := AutoMap[Alpha, Foo](a) if err != nil { fmt.Println(err) t.Fail() } fmt.Println("f.nested.info:", f.Nested.Info) } func AutoMap[S, T any](source S) (target T, err error) { targetStruct := reflect.ValueOf(&target).Elem() sourceStruct := reflect.ValueOf(&source).Elem() // .Type and .Kind directly did not work. nestedSourceType := ??? // I want this to be type Beta. nestedTargetType := ??? // I want this to be type Bar. sourceInterface := sourceStruct.Interface() t, err := AutoMap[nestedSourceType, nestedTargetType](sourceInterface) if err != nil { return target, err } target = t return target, nil }
登錄后復制
解決方法
按照@mkopriva的建議,我想分享一個簡單的解決方案來解決我遇到的問題。
請隨意糾正或改進它,但請記住,我故意不包括下面的各種檢查和斷言。
(go playground 示例)
type Alpha struct { NestedOnce Beta } type Beta struct { NestedTwice Gamma } type Gamma struct { Info string } type Foo struct { NestedOnce Bar } type Bar struct { NestedTwice Baz } type Baz struct { Info string } func TestAutoMap(t *testing.T) { g := Gamma{"Hello from Gamma!"} b := Beta{g} a := Alpha{b} f, err := AutoMap[Foo](a) if err != nil { fmt.Println(err) t.Fail() } else { fmt.Println("Foo.NestedOnce.NestedTwice.Info:", f.NestedOnce.NestedTwice.Info) } } func AutoMap[T any](source any) (target T, err error) { // Peel off 'any' from the function parameter type. sourceStruct := reflect.ValueOf(&source).Elem().Elem() targetStruct := reflect.ValueOf(&target).Elem() err = autoMap(sourceStruct, targetStruct) return target, err } func autoMap(s, t reflect.Value) error { sourceField := s.Field(0) targetField := t.Field(0) if sourceField.Kind() == reflect.Struct { err := autoMap(sourceField, targetField) if err != nil { return err } return nil } targetField.Set(sourceField) return nil }
登錄后復制