Maison > développement back-end > Golang > le corps du texte

Comment instancier un pointeur non nul vers un paramètre de type à l'aide d'un Go générique ?

WBOY
Libérer: 2024-02-11 17:36:11
avant
405 Les gens l'ont consulté

如何使用泛型 Go 实例化类型参数的非零指针?

l'éditeur php Xigua vous présentera comment utiliser des pointeurs non nuls de paramètres de type d'instanciation génériques en langage Go. Dans le langage Go, les génériques constituent une fonctionnalité puissante qui peut augmenter la flexibilité et la réutilisabilité du code. Lorsque nous devons instancier un pointeur différent de zéro dans une fonction ou une méthode générique, nous pouvons utiliser des assertions de type et une réflexion pour y parvenir. En utilisant ces techniques, nous pouvons créer une instance de pointeur non nulle au moment de l'exécution en fonction du type spécifique du paramètre de type, obtenant ainsi la flexibilité et la polyvalence des génériques. Examinons de plus près la méthode de mise en œuvre spécifique.

Contenu de la question

Maintenant que les paramètres de type sont disponibles sur golang/go:master, j'ai décidé de l'essayer. Il semble que j'ai atteint une limitation que je ne trouve pas dans la proposition de paramètres de type. (Ou j'ai dû le manquer).

Je souhaite écrire une fonction qui renvoie une tranche de valeurs de type générique avec des contraintes de type d'interface. Si le type transmis est une implémentation avec un récepteur de pointeur, comment l'instancier ?

type SetGetter[V any] interface {
    Set(V)
    Get() V
}

// SetGetterSlice turns a slice of type V into a slice of type T,
// with T.Set() called for each entry in values.
func SetGetterSlice[V any, T SetGetter[V]](values []V) []T {
    out := make([]T, len(values))

    for i, v := range values {
        out[i].Set(v) // panic if T has pointer receiver!
    }

    return out
}
Copier après la connexion

Lors de l'utilisation de *Count 类型作为 T 调用上述 SetGetterSlice() 函数时,此代码将在调用 Set(v) 时出现混乱。 (Go2go 游乐场)毫不奇怪,因为基本上代码创建了 nil tranches de pointeurs :

// Count implements SetGetter interface
type Count struct {
    x int
}

func (c *Count) Set(x int) { c.x = x }
func (c *Count) Get() int  { return c.x }

func main() {
    ints := []int{1, 2, 3, 4, 5}

    sgs := SetGetterSlice[int, *Count](ints)
    
    for _, s := range sgs {
        fmt.Println(s.Get())
    }
}
Copier après la connexion

Variation de la même question

Cette idée ne fonctionne pas, je n'arrive pas à trouver un moyen simple d'instancier la valeur indiquée.

  1. out[i] = new(T) 将导致编译失败,因为它返回 *T,其中类型检查器希望查看 T.
  2. Appelez*new(T) 进行编译,但会导致相同的运行时恐慌,因为 new(T) 返回 **Count 在这种情况下,其中指向 Count 的指针仍然是 nil.
  3. Changer le type de retour en un fragment de pointeur vers T entraînera l'échec de la compilation :
func SetGetterSlice[V any, T SetGetter[V]](values []V) []*T {
    out := make([]*T, len(values))

    for i, v := range values {
        out[i] = new(T)
        out[i].Set(v) // panic if T has pointer receiver
    }

    return out
}

func main() {
    ints := []int{1, 2, 3, 4, 5}

    SetGetterSlice[int, Count](ints)
    // Count does not satisfy SetGetter[V]: wrong method signature
}
Copier après la connexion

Solution

La seule solution que j'ai trouvée jusqu'à présent est d'exiger le passage du constructeur à une fonction générique. Mais cela semble faux et un peu ennuyeux. Si func F(T interface{})() []T est une syntaxe parfaitement valide, pourquoi est-elle nécessaire ?

func SetGetterSlice[V any, T SetGetter[V]](values []V, constructor func() T) []T {
    out := make([]T, len(values))

    for i, v := range values {
        out[i] = constructor()
        out[i].Set(v)
    }

    return out
}

// ...
func main() {
    ints := []int{1, 2, 3, 4, 5}

    SetGetterSlice[int, *Count](ints, func() *Count { return new(Count) })
}
Copier après la connexion

Résumé

Mes questions (par ordre de priorité) :

  1. Est-ce que j'oublie quelque chose d'évident ?
  2. Est-ce une limitation des génériques dans Go ? Est-ce aussi bon que possible ?
  3. Cette limitation est-elle connue ou dois-je soulever un problème dans le projet Go ?

Solution de contournement

Fondamentalement, vous devez ajouter un paramètre de type à la contrainte pour rendre T convertible en son type de pointeur. Dans sa forme la plus basique, la technique ressemble à ceci (avec des contraintes d'anonymat) :

func Foo[T any, PT interface { *T; M() }]() {
    p := PT(new(T))
    p.M() // calling method on non-nil pointer
}
Copier après la connexion

Aire de jeux :https://www.php.cn/link/24aef8cb3281a2422a59b51659f1ad2e

<小时>

Solution étape par étape

Vos contraintes SetGetter 已经声明了类型参数 V, nous modifions donc légèrement l'exemple ci-dessus :

// V is your original type param
// T is the additional helper param
type SetGetter[V any, T any] interface {
    Set(V)
    Get() V
    *T
}
Copier après la connexion

Puis définissez SetGetterSlice 函数,其类型参数为 T any,其目的只是实例化约束 SetGetter.

Vous pouvez ensuite convertir l'expression &out[i] en type pointeur et appeler avec succès la méthode sur le récepteur du pointeur :

// T is the type with methods with pointer receiver
// PT is the SetGetter constraint with *T
func SetGetterSlice[V any, T any, PT SetGetter[V, T]](values []V) []T {
    out := make([]T, len(values))

    for i, v := range values {
        // out[i] has type T
        // &out[i] has type *T
        // PT constraint includes *T
        p := PT(&out[i]) // valid conversion!
        p.Set(v)         // calling with non-nil pointer receiver
    }

    return out
}
Copier après la connexion

Programme complet :

CFE57E536C89530D9A8C38E10967A10D

Cela devient plus détaillé car SetGetterSlice nécessite désormais trois paramètres de type : le V d'origine plus SetGetterSlice 现在需要三个类型参数:原始 V 加上 T (带有指针接收器的类型)和 PT (新约束)。然而,当您调用该函数时,您可以省略第三个 - 通过类型推断,实例化 PT SetGetter[V,T] 所需的类型参数 VT (le type avec le récepteur du pointeur) et PT< /code> ( nouvelle contrainte). Cependant, lorsque vous appelez la fonction, vous pouvez omettre la troisième inférence de type, les paramètres de type <code>V requis pour instancier PT SetGetter[V,T] et

C'est tout connu :

SetGetterSlice[int, Count](ints)
Copier après la connexion
Aire de jeux :https://www.php.cn/link/6b061fc28f7473418a006dfa832708b1🎜

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!

Étiquettes associées:
source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal