Maison  >  Article  >  développement back-end  >  Comment attribuer ou restituer un T générique soumis à une union ?

Comment attribuer ou restituer un T générique soumis à une union ?

WBOY
WBOYavant
2024-02-09 20:30:19791parcourir

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

l'éditeur php Yuzai vous propose un article sur la façon d'attribuer ou de renvoyer un T universel soumis aux contraintes syndicales. Lors de l’écriture de code PHP, nous devons parfois définir un type de données, qui peut être une combinaison de plusieurs types différents. C'est le type d'union. Cependant, nous pouvons rencontrer une certaine confusion lorsque nous essayons d'attribuer ou de renvoyer un tel T générique contraint par l'union. Cet article vous donnera une réponse détaillée sur la façon de résoudre ce problème, vous permettant de mieux appliquer le T universel du type union.

Contenu de la question

En d'autres termes, comment implémenter une solution spécifique à un type pour différents types dans un ensemble de types d'union ?

Étant donné le code suivant...

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
}

Le compilateur affiche une erreur :

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

Existe-t-il un moyen de fournir des implémentations pour tous les fieldtype possibles ?

J'aime...

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
}

Tous les conseils sont les bienvenus.

Solution de contournement

Cette erreur se produit car les opérations impliquant des paramètres de type (y compris l'affectation et le retour) doivent être valides pour tous les types de leur ensemble de types. Si string | int, il n'y a pas d'opération courante pour initialiser leurs valeurs à partir de chaînes.

Mais il vous reste encore quelques options :

Tapez allumage

t

Vous utilisez un champ de type générique t 的字段,并临时将具体类型的值设置到 接口{}/any 中。然后将接口键入断言回 t 以返回它。请注意,此断言未经检查,因此如果由于某种原因 ret 持有不属于 t dans un commutateur de type et définissez temporairement la valeur du type spécifique dans le interface{}/any. Tapez ensuite à nouveau l'assertion d'interface dans

pour la renvoyer. Notez que cette assertion n'est pas vérifiée, donc si pour une raison quelconque ret contient quelque chose qui ne fait pas partie de l'ensemble de types

, vous pourriez paniquer. Bien sûr, vous pouvez le vérifier avec la virgule -ok, mais c'est toujours une assertion d'exécution : *t
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
}
Tapez allumage

t Vous pouvez simplifier davantage le code ci-dessus et vous débarrasser de l'interface vide. Dans ce cas, vous obtenez l'adresse d'une variable de type et ouvrez le type pointeur.

Ceci est entièrement vérifié au moment de la compilation

 : t 值转换为 interface{}/any 才能在类型开关中使用它。您无法直接在 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
}

Notez que dans les deux cas, vous devez convertir la valeur

en interface{}/any pour l'utiliser dans un commutateur de type. Vous ne pouvez pas taper switch directement sur os.lookupenv. Aire de jeux avec

carte simulée : 🎜https://www.php.cn/link/498bce62bd2bda584246701fa0166482 🎜🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer