问题内容
上下文:我正在编写一个通用自动映射器,它采用两种类型的结构,检查所述结构的每个字段是否有给定的标签,然后将值从源结构复制到目标结构,假设它们具有匹配的标签和类型。每当结构字段是另一个(嵌套)结构时,我希望自动映射器函数执行递归调用,自动映射到兔子洞。
问题:我只能传递根结构的具体类型。一旦我进入使用反射的通用函数,尝试提取嵌套的结构类型似乎是不可能的。 虽然我可以传递 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的建议,我想分享一个简单的解决方案来解决我遇到的问题。 p>
请随意纠正或改进它,但请记住,我故意不包括下面的各种检查和断言。
(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
}
以上就是如何使用反射提取类型参数的详细内容,更多请关注编程网其它相关文章!