Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Cara memanggil fungsi generik dalam Go dengan menghantar Type melalui refleksi

Cara memanggil fungsi generik dalam Go dengan menghantar Type melalui refleksi

王林
王林ke hadapan
2024-02-05 22:21:031225semak imbas

如何通过反射传递 Type 来调用 Go 中的泛型函数

Kandungan soalan

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&#160;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?


Jawapan betul


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&#160;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!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam