Heim  >  Artikel  >  Backend-Entwicklung  >  So extrahieren Sie Typparameter mithilfe von Reflektion

So extrahieren Sie Typparameter mithilfe von Reflektion

王林
王林nach vorne
2024-02-12 17:24:05575Durchsuche

So extrahieren Sie Typparameter mithilfe von Reflektion

Frageninhalt

Kontext: Ich schreibe einen generischen Automapper, der zwei Arten von Strukturen akzeptiert, prüft, ob jedes Feld dieser Struktur eine bestimmte Bezeichnung hat, und dann die Werte von der Quellstruktur in Zielstrukturen kopiert , vorausgesetzt, sie haben passende Tags und Typen. Immer wenn ein Strukturfeld eine andere (verschachtelte) Struktur ist, möchte ich, dass die Automapper-Funktion einen rekursiven Aufruf ausführt, der das Kaninchenloch automatisch abbildet.

Problem: Ich kann nur den konkreten Typ der Wurzelstruktur übergeben. Sobald ich mit der Reflektion in die generische Funktion einsteige, scheint es unmöglich, den verschachtelten Strukturtyp zu extrahieren. Obwohl ich value.interface() als Parameter übergeben kann, muss ich dennoch den Typparameter übergeben.

Hier ist ein vereinfachter Code, um das Problem zu veranschaulichen.

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
}

Lösung

Dem Rat von @mkopriva folgend, wollte ich eine einfache Lösung für das Problem, das ich hatte, teilen. p>

Fühlen Sie sich frei, es zu korrigieren oder zu verbessern, aber denken Sie daran, dass ich unten absichtlich verschiedene Überprüfungen und Behauptungen nicht aufgeführt habe.

(Beispiel zum Spielplatz gehen)

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
}

Das obige ist der detaillierte Inhalt vonSo extrahieren Sie Typparameter mithilfe von Reflektion. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen