Cara memanggil fungsi generik dalam Go dengan menghantar Type melalui refleksi

王林
Lepaskan: 2024-02-05 22:21:03
ke hadapan
1224 orang telah melayarinya

如何通过反射传递 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 }
}
Salin selepas log masuk

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.

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

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

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!

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