Maison  >  Article  >  développement back-end  >  Comment puis-je remplir efficacement une tranche d'interfaces avec des instances d'un type concret dans Golang, tout en garantissant la sécurité des types et en évitant les paniques potentielles ?

Comment puis-je remplir efficacement une tranche d'interfaces avec des instances d'un type concret dans Golang, tout en garantissant la sécurité des types et en évitant les paniques potentielles ?

Patricia Arquette
Patricia Arquetteoriginal
2024-10-26 03:59:02285parcourir

How can I efficiently fill a slice of interfaces with instances of a concrete type in Golang, while ensuring type safety and avoiding potential panics?

Fonction de remplissage générique pour les tranches d'interfaces et les types de béton

Dans Golang, il est possible de définir des fonctions génériques à l'aide de génériques. Lorsqu'il s'agit de tranches d'interfaces et de types concrets, une tâche courante consiste à initialiser tous les éléments de la tranche avec un type concret. Considérons la fonction suivante, qui vise à remplir une tranche de pointeurs vers un type X avec de nouvelles instances de X :

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

Cette fonction fonctionne comme prévu pour les tranches de tout type. Cependant, des défis surviennent lorsque l'on tente d'étendre ce comportement à des tranches d'interfaces et de spécifier un type concret pour l'élément (Y).

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

Lorsque l'on contraint X et Y à any, la relation entre les interfaces et les implémenteurs est perdu. Le compilateur traite X et Y comme des types distincts, empêchant les affectations entre eux dans le corps de la fonction.

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 approche peut panique si Y n'implémente pas X, comme dans le cas de sync.Mutex (un type de pointeur) implémentant sync.Locker. De plus, puisque la valeur zéro pour un type de pointeur est nulle, cette méthode n'apporte pas d'amélioration significative par rapport à l'utilisation de make([]X, n), qui initialise également la tranche avec des valeurs nulles.

Une solution plus efficace consiste à utiliser une fonction constructeur au lieu d'un deuxième paramètre de type :

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

Cette fonction prend un paramètre supplémentaire f, qui est une fonction qui renvoie une instance de X. Cela permet plus de flexibilité et prend en charge le remplissage des interfaces avec des types de béton. Par exemple, pour initialiser une tranche de sync.Locker avec des éléments sync.Mutex, le code suivant peut être utilisé :

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

En utilisant cette approche, les tranches d'interfaces peuvent être efficacement remplies d'instances d'un objet concret. tapez, offrant une solution pratique et sûre.

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