Maison  >  Article  >  développement back-end  >  Comment remplir une tranche avec des implémentations concrètes à l'aide de génériques et d'interfaces Golang ?

Comment remplir une tranche avec des implémentations concrètes à l'aide de génériques et d'interfaces Golang ?

Mary-Kate Olsen
Mary-Kate Olsenoriginal
2024-10-26 10:33:02704parcourir

How to Fill a Slice with Concrete Implementations Using Golang Generics and Interfaces?

Golang Generics : combiner des interfaces et des implémentations concrètes

Dans Go 1.18, les génériques permettent aux développeurs de définir des fonctions et des structures de données qui fonctionnent sur un plus large éventail de types. Cependant, un scénario spécifique est apparu dans lequel les utilisateurs cherchent à utiliser des génériques avec des interfaces tout en fournissant également un type concret pour les paramètres de type générique.

Problème

Considérez la fonction suivante qui vise à remplir une tranche avec nouvelles instances d'un type concret :

<code class="go">func Fill[X any](slice []*X) {
   for i := range slice {
      slice[i] = new(X)
   }
}</code>

Cette fonction fonctionne comme prévu lors du remplissage d'une tranche de pointeurs vers un type spécifique, tel que []*int. Cependant, si la tranche est constituée d'interfaces et que la fonction est appelée avec un type concret pour le paramètre générique, la compilation échoue.

<code class="go">xs := make([]sync.Locker, 10) // fill with nils
Fill[sync.Locker,sync.Mutex](xs) // ouch</code>

Cause

Le problème se pose car la contrainte des deux paramètres de type X et Y à any supprime la relation entre l'interface et sa mise en œuvre concrète. Au moment de la compilation, on sait seulement que X et Y sont des types distincts.

Solution

Pour résoudre ce problème, une assertion explicite peut être utilisée :

<code class="go">func Fill[X, Y any](slice []X) {
    for i := range slice {
        slice[i] = any(*new(Y)).(X)
    }
}</code>

Cependant, cette solution introduit des paniques d'exécution potentielles si Y n'implémente pas X. De plus, si Y est un type pointeur, les informations de type de base sont perdues, ce qui entraîne des valeurs nulles au lieu d'instances du type concret souhaité.

Une meilleure approche consiste à utiliser une fonction constructeur au lieu d'un deuxième paramètre générique, comme démontré ci-dessous :

<code class="go">func main() {
    xs := make([]sync.Locker, 10)
    Fill(xs, func() sync.Locker { return &sync.Mutex{} })
}

func Fill[X any](slice []X, f func() X) {
    for i := range slice {
        slice[i] = f()
    }
}</code>

Cette solution fournit un moyen plus robuste et idiomatique de remplir une tranche avec des instances d'un type concret spécifique tout en maintenir la sécurité des types.

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