Rumah >pembangunan bahagian belakang >Golang >Cara memanggil fungsi generik dalam Go dengan menghantar Type melalui refleksi
Saya mempunyai aplikasi Go yang menerima respons JSON yang berbeza untuk API yang sama, jadi saya cuba menulis unmarshaller tersuai yang akan cuba memproses setiap kemungkinan respons JSON sehingga ia menemui satu respons yang betul.
Untuk melakukan ini, saya mencipta fungsi generik untuk unmarshal JSON, dan saya mahu memanggilnya menggunakan jenis yang diperoleh daripada refleksi.
Contohnya:
package main import ( "bytes" "encoding/json" "fmt" "reflect" ) type JSONHandler struct{} func (handler *JSONHandler) Unmarshal(data []byte) error { t := reflect.TypeOf(*handler) for i := 0; i < t.NumField(); i++ { fieldType := t.Field(i) fmt.Printf("Trying to unmarshal: %s\n", fieldType.Name) result, err := unmarshal[fieldType](data) // fieldType (variable of type reflect.StructField) is not a typecompiler (NotAType) if err == nil { fmt.Printf("result: %s\n", result) break } } return nil } func unmarshal[T interface{}](data []byte) (*T, error) { obj := new(T) reader := bytes.NewReader(data) decoder := json.NewDecoder(reader) decoder.DisallowUnknownFields() err := decoder.Decode(obj) if err != nil { return nil, err } return obj, nil } type User struct { Username *string `json:"username,omitempty"` Password *string `json:"password,omitempty"` } type UserError struct { Error *string `json:"error,omitempty"` Code *int `json:"code,omitempty"` } type UserOrError struct { User *User UserError *UserError JSONHandler } var userJson = `{ "username": "[email protected]", "password": "password" }` func main() { user := new(UserOrError) result := user.Unmarshal([]byte(userJson)) // { User: something, UserError: nil } }
Walau bagaimanapun, pengkompil Go memberi saya ralat ini: fieldType (reflect.StructField 类型的变量) 不是类型编译器 (NotAType)
.
Adakah terdapat cara untuk menghantar parameter pantulan kepada fungsi generik?
Soalan ini di luar skop fungsi umum Go.
Gunakan refleksi.Baharu untuk mencipta nilai yang diberi refleksi.Jenis nilai itu. p>
Go tidak mempunyai warisan. Kaedah Unmarshal dalam soalan beroperasi pada jenis yang tidak mempunyai medan. Dibetulkan dengan menghantar "pengendali" ke fungsi biasa.
// Unmarshal unmarshals data to each field type in handler // and returns the first successful result. The handler argument // must be a pointer to a struct. func Unmarshal(handler any, data []byte) (any, error) { t := reflect.TypeOf(handler).Elem() for i := 0; i < t.NumField(); i++ { fieldType := t.Field(i) v := reflect.New(fieldType.Type) decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() err := decoder.Decode(v.Interface()) if err == nil { return v.Elem().Interface(), err } } return nil, errors.New("no matching type") }
Gunakan fungsi Marshal seperti ini:
type UserOrError struct { User *User UserError *UserError } var userJson = `{ "username": "<a href="https://www.php.cn/link/89fee0513b6668e555959f5dc23238e9" class="__cf_email__" data-cfemail="0e646166604e6b636f6762206d6163">[email protected]</a>", "password": "password" }` result, err := Unmarshal(&UserOrError{}, []byte(userJson)) // { User: something, UserError: nil } fmt.Printf("err=%v, result=%#v\n", err, result)
https://www.php.cn/link/c76e4b2fa54f8506719a5c0dc14c2eb9
Atas ialah kandungan terperinci Cara memanggil fungsi generik dalam Go dengan menghantar Type melalui refleksi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!