首頁 >後端開發 >Golang >如何分配或傳回受聯合約束的通用 T?

如何分配或傳回受聯合約束的通用 T?

WBOY
WBOY轉載
2024-02-09 20:30:19890瀏覽

如何分配或返回受联合约束的通用 T?

php小編魚仔為大家帶來了一篇關於如何分配或回傳受聯合約束的通用T的文章。在編寫PHP程式碼時,有時我們需要定義一種資料類型,該類型可以是多個不同類型的結合。這就是聯合類型。然而,當我們嘗試指派或傳回這種受聯合約束的通用T時,可能會遇到一些困惑。本文將為您詳細解答如何處理這個問題,讓您更能應用聯合類型的通用T。

問題內容

換句話說,如何為聯合型別集中的不同型別實作特定於型別的解決方案?

給出以下程式碼...

type fieldtype interface {
    string | int
}

type field[t fieldtype] struct {
    name         string
    defaultvalue t
}

func newfield[t fieldtype](name string, defaultvalue t) *field[t] {
    return &field[t]{
        name:         name,
        defaultvalue: defaultvalue,
    }
}

func (f *field[t]) name() string {
    return f.name
}

func (f *field[t]) get() (t, error) {
    value, ok := os.lookupenv(f.name)
    if !ok {
        return f.defaultvalue, nil
    }
    return value, nil
}

編譯器顯示錯誤:

field.go:37:9: cannot use value (variable of type string) as type t in return statement

有沒有辦法為所有可能的 fieldtypes 提供實作?

喜歡...

func (f *Field[string]) Get() (string, error) {
    value, ok := os.LookupEnv(f.name)
    if !ok {
        return f.defaultValue, nil
    }
    return value, nil
}

func (f *Field[int]) Get() (int, error) {
    raw, ok := os.LookupEnv(f.name)
    if !ok {
        return f.defaultValue, nil
    }
    value, err := strconv.ParseInt(raw, 10, 64)
    if err != nil {
        return *new(T), err
    }
    return int(value), nil
}

歡迎任何提示。

解決方法

發生該錯誤的原因是涉及類型參數的操作(包括賦值和返回)必須對其類型集中的所有類型都有效。 如果是 string | int,沒有通用的操作來從字串初始化它們的值。

但是您仍然有幾個選擇:

t 上的型別切換

您在類型開關中使用通用類型 t 的字段,並將具體類型的值暫時設定到 介面{}/any# 中。然後將介面鍵入斷言回 t 以傳回它。請注意,此斷言未經檢查,因此如果由於某種原因 ret 持有不屬於 t 類型集中的內容,則可能會出現恐慌。當然你可以用逗號-ok檢查它,但它仍然是一個運行時斷言:

func (f *field[t]) get() (t, error) {
    value, ok := os.lookupenv(f.name)
    if !ok {
        return f.defaultvalue, nil
    }
    var ret any
    switch any(f.defaultvalue).(type) {
    case string:
        ret = value

    case int:
        // don't actually ignore errors
        i, _ := strconv.parseint(value, 10, 64)
        ret = int(i)
    }
    return ret.(t), nil
}

*t 上的型別切換

您可以進一步簡化上面的程式碼並擺脫空介面。在本例中,您取得 t 類型變數的位址並開啟指標類型。 這在編譯時進行了完全類型檢查

func (f *Field[T]) Get() (T, error) {
    value, ok := env[f.name]
    if !ok {
        return f.defaultValue, nil
    }

    var ret T
    switch p := any(&ret).(type) {
    case *string:
        *p = value

    case *int:
        i, _ := strconv.ParseInt(value, 10, 64)
        *p = int(i)
    }
    // ret has the zero value if no case matches
    return ret, nil
}

請注意,在這兩種情況下,您都必須將t 值轉換為interface{}/any 才能在類型開關中使用它。您無法直接在 t 上進行類型切換。

有模擬 os.lookupenv 地圖的遊樂場:https://www.php.cn/link/498bce62bd2bda584246701fa0166482

以上是如何分配或傳回受聯合約束的通用 T?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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