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 }
Mengikut nasihat @mkopriva Saya ingin berkongsi penyelesaian mudah untuk masalah yang saya hadapi. p>
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 }
Atas ialah kandungan terperinci Bagaimana untuk mengekstrak parameter jenis menggunakan refleksi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!