首頁 >後端開發 >Golang >如何透過反射傳遞 Type 來呼叫 Go 中的泛型函數

如何透過反射傳遞 Type 來呼叫 Go 中的泛型函數

王林
王林轉載
2024-02-05 22:21:031256瀏覽

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

問題內容

我有一個Go 應用程序,可以接收同一API 的不同JSON 回應,因此我嘗試編寫一個自訂解組器,它將嘗試處理每個可能的JSON 回應,直到找到正確的回應。

為此,我創建了一個通用函數來解組 JSON,並且我想使用從反射獲得的類型來呼叫它。

例如:

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 }
}

但是,Go 編譯器給了我這個錯誤:fieldType (reflect.StructField 類型的變數) 不是類型編譯器 (NotAType)

有沒有辦法將反射參數傳遞給泛型函數?


正確答案


這個問題超出了 Go 通用功能的範圍。

使用 reflect.New 建立一個給定該值的reflect.Type的值。 p>

Go 沒有繼承。問題中的 Unmarshal 方法對沒有欄位的類型進行操作。透過將“處理程序”傳遞給普通函數來修復。

// 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")
}

像這樣使用 Marshal 函數:

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

以上是如何透過反射傳遞 Type 來呼叫 Go 中的泛型函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除