jeudi 6 avril 2023

How to extract type parameters using reflection

Context: I'm writing a generic auto-mapper that takes two types of structs, checks each field of said structs for a given tag, then copies the value from the source struct to the target struct assuming that they have matching tags and types. Whenever a struct field is another (nested) struct, I want the auto-mapper function to do a recursive call, auto-mapping all the way down the rabbit hole.

Problem: I'm only able to pass the concrete type of the root structs. Once I'm inside the generic function that's using reflection, trying to extract the nested struct types doesn't seem possible. While I can pass the Value.Interface() as an argument, I still need to pass the type parameters as well.

Here is some simplified code to show the problem.

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
}




Aucun commentaire:

Enregistrer un commentaire