問題內容
上下文:我正在編寫一個通用自動映射器,它采用兩種類型的結構,檢查所述結構的每個字段是否有給定的標簽,然后將值從源結構復制到目標結構,假設它們具有匹配的標簽和類型。每當結構字段是另一個(嵌套)結構時,我希望自動映射器函數執行遞歸調用,自動映射到兔子洞。
問題:我只能傳遞根結構的具體類型。一旦我進入使用反射的通用函數,嘗試提取嵌套的結構類型似乎是不可能的。
雖然我可以傳遞 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
}
登錄后復制






