Bagaimana untuk mengekstrak parameter jenis menggunakan refleksi

王林
Lepaskan: 2024-02-12 17:24:05
ke hadapan
600 orang telah melayarinya

Bagaimana untuk mengekstrak parameter jenis menggunakan refleksi

Kandungan soalan

Konteks: Saya sedang menulis automapper generik yang mengambil dua jenis struktur, menyemak sama ada setiap medan struktur tersebut mempunyai label tertentu, dan kemudian menyalin nilai dari struktur sumber kepada struktur Sasaran , dengan mengandaikan mereka mempunyai teg dan jenis yang sepadan. Setiap kali medan struct ialah satu lagi struct (bersarang), saya mahu fungsi automapper melakukan panggilan rekursif yang secara automatik memetakan ke bawah lubang arnab.

Masalah: Saya hanya boleh melepasi jenis konkrit struktur akar. Sebaik sahaja saya masuk ke fungsi generik menggunakan refleksi, cuba mengekstrak jenis struct bersarang nampaknya mustahil. Walaupun saya boleh lulus value.interface() sebagai parameter, saya masih perlu lulus parameter jenis.

Berikut ialah beberapa kod ringkas untuk menunjukkan masalah.

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
}
Salin selepas log masuk

Penyelesaian

Mengikut nasihat @mkopriva Saya ingin berkongsi penyelesaian mudah untuk masalah yang saya hadapi.

Jangan ragu untuk membetulkan atau memperbaikinya, tetapi perlu diingat bahawa saya sengaja tidak memasukkan pelbagai semakan dan penegasan di bawah.

(pergi contoh taman permainan)

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
}
Salin selepas log masuk

Atas ialah kandungan terperinci Bagaimana untuk mengekstrak parameter jenis menggunakan refleksi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:stackoverflow.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan