Table des matières
? Qu'y a-t-il à l'intérieur
? Programmes génériques de base
Maison développement back-end Golang Generics in Go : transformer la réutilisabilité du code

Generics in Go : transformer la réutilisabilité du code

Jan 08, 2025 am 06:20 AM

Les génériques, introduits dans Go 1.18, ont révolutionné la manière d'écrire du code réutilisable et de type sécurisé. Les génériques apportent flexibilité et puissance tout en conservant la philosophie de simplicité de Go. Cependant, comprendre les nuances, les avantages et la façon dont les génériques se comparent aux approches traditionnelles (comme interface{} ) nécessite un examen plus approfondi.

Explorons les subtilités des génériques, approfondissons les contraintes, comparons les génériques à l'interface{} et démontrons leurs applications pratiques. Nous aborderons également les considérations de performances et les implications en matière de taille binaire. Allons-y !

Qu’est-ce que les génériques ?

Les génériques permettent aux développeurs d'écrire des fonctions et des structures de données pouvant fonctionner sur n'importe quel type tout en maintenant la sécurité des types. Au lieu de s'appuyer sur interface{}, qui implique des assertions de type au moment de l'exécution, les génériques vous permettent de spécifier un ensemble de contraintes qui dictent les opérations autorisées sur les types.

Syntaxe

func FunctionName[T TypeConstraint](parameterName T) ReturnType {
    // Function body using T
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

T : Un paramètre de type, représentant un espace réservé pour le type.

TypeConstraint : restreint le type de T à un type spécifique ou à un ensemble de types.

parameterName T : Le paramètre utilise le type générique T.

ReturnType : La fonction peut également renvoyer une valeur de type T.

Exemple

func Sum[T int | float64](a, b T) T {
    return a + b
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

func Sum : Déclare le nom de la fonction, Sum

[T int | float64] : Spécifie une liste de paramètres de type qui introduit T comme paramètre de type, limité à des types spécifiques (int ou float64). La fonction Somme ne peut prendre que des paramètres int ou float64, pas en combinaison, les deux doivent être soit int, soit float64. Nous explorerons cela plus en détail dans les sections ci-dessous.

(a, b T): Déclare deux paramètres, a et b, tous deux de type T (le type générique ).

T : Spécifie le type de retour de la fonction, qui correspond au paramètre de type T.

Contraintes : éléments constitutifs des génériques

Les contraintes définissent quelles opérations sont valides pour un type générique. Go fournit des outils puissants pour les contraintes, y compris le package de contraintes expérimentales (golang.org/x/exp/constraints).

Contraintes intégrées

Go a introduit des contraintes intégrées avec les génériques pour assurer la sécurité des types tout en permettant une flexibilité dans la définition de code réutilisable et générique. Ces contraintes permettent aux développeurs d'appliquer des règles sur les types utilisés dans les fonctions ou types génériques.

Go a des contraintes intégrées ci-dessous

  1. any : représente n'importe quel type. C'est un alias pour interface{}. Ceci est utilisé lorsqu'aucune contrainte n'est nécessaire
func FunctionName[T TypeConstraint](parameterName T) ReturnType {
    // Function body using T
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
  1. comparable : autorise les types qui prennent en charge la comparaison d'égalité (== et !=). Utile pour les clés de cartes, la détection des doublons ou les contrôles d'égalité. Cela ne peut pas être utilisé pour les cartes, les tranches et les fonctions, car ces types ne prennent pas en charge la comparaison directe.
func Sum[T int | float64](a, b T) T {
    return a + b
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Contraintes expérimentales

  1. constraints.Complex : autorise les types numériques complexes (complex64 et complex128).
  2. constraints.Float : autorise les types numériques float (float32 et float64)
  3. constraints.Integer : autorise tout entier signé et non signé (int8, int16, int32, int64, int, uint8, uint16, uint32, uint64 et uint)
  4. constraints.Signed : autorise tout entier signé (int8, int16, int32, int64 et int)
  5. constraints.Unsigned : autorise tout entier non signé (uint8, uint16, uint32, uint64 et uint).
  6. constraint.Ordered : autorise les types qui permettent la comparaison (<. <=, >, >=), tous les types numériques et chaînes sont pris en charge (int, float64, string, etc.).
func PrintValues[T any](values []T) {
    for _, v := range values {
        fmt.Println(v)
    }
}
Copier après la connexion
Copier après la connexion

Contraintes personnalisées

Les contraintes personnalisées sont des interfaces qui définissent un ensemble de types ou de comportements de type qu'un paramètre de type générique doit satisfaire. En créant vos propres contraintes, nous pouvons ;

  • Limiter les types à un sous-ensemble spécifique, tel que les types numériques.

  • Exiger des types pour implémenter des méthodes ou des comportements spécifiques.

  • Ajoutez plus de contrôle et de spécificité à vos fonctions et types génériques.

Syntaxe

func CheckDuplicates[T comparable](items []T) []T {
    seen := make(map[T]bool)
    duplicates := []T{}
    for _, item := range items {
        if seen[item] {
            duplicates = append(duplicates, item)
        } else {
            seen[item] = true
        }
    }
    return duplicates
}
Copier après la connexion
Copier après la connexion

Exemple

import (
     "golang.org/x/exp/constraints"
     "fmt"
)

func SortSlice[T constraints.Ordered](items []T) []T {
    sorted := append([]T{}, items...) // Copy slice
    sort.Slice(sorted, func(i, j int) bool {
        return sorted[i] < sorted[j]
    })
    return sorted
}

func main() {
    nums := []int{5, 2, 9, 1}
    fmt.Println(SortSlice(nums)) // Output: [1 2 5 9]

    words := []string{"banana", "apple", "cherry"}
    fmt.Println(SortSlice(words)) // Output: [apple banana cherry]
}
Copier après la connexion
Copier après la connexion

La fonction Somme peut être appelée en utilisant uniquement les paramètres int, int64 et float64.

Contraintes par méthode

Si vous souhaitez imposer qu'un type doive implémenter certaines méthodes, vous pouvez le définir en utilisant ces méthodes.

type Numeric interface {
    int | float64 | uint
}
Copier après la connexion
Copier après la connexion

La contrainte Formatter requiert que tout type utilisé comme T doit avoir une méthode Format qui renvoie un chaîne.

Combinaison de contraintes

Les contraintes personnalisées peuvent combiner des ensembles de types et des exigences de méthode

type Number interface {
    int | int64 | float64
}

func Sum[T Number](a, b T) T {
    return a + b
}
Copier après la connexion

Cette contrainte inclut à la fois des types spécifiques (int, float54) et nécessite la présence d'une méthode abs.

Génériques vs interface{}

Avant l'introduction des génériques, l'interface{} était utilisée pour obtenir de la flexibilité. Cependant, cette approche a des limites.

Sécurité

  • interface{} : s'appuie sur des assertions de type d'exécution, augmentant le risque d'erreurs au moment de l'exécution.

  • Génériques : offre une sécurité de type au moment de la compilation, détectant les erreurs dès le début du développement.

Performance

  • interface{} : plus lente en raison de vérifications de type d'exécution supplémentaires.

  • Génériques : plus rapide, car le compilateur génère des chemins de code optimisés spécifiques aux types.

Lisibilité du code

  • interface{} : souvent verbeuse et moins intuitive, ce qui rend le code plus difficile à maintenir.

  • Génériques : une syntaxe plus propre conduit à un code plus intuitif et maintenable.

Taille binaire

  • interface{} : génère des binaires plus petits car elle ne duplique pas le code pour différents types.

  • Génériques : augmente légèrement la taille du binaire en raison de la spécialisation du type pour de meilleures performances.

Exemple

func FunctionName[T TypeConstraint](parameterName T) ReturnType {
    // Function body using T
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le code fonctionne bien, l'assertion de type est une surcharge. La fonction Add peut être appelée avec n'importe quel argument, les paramètres a et b peuvent être de types différents, mais le code plantera lors de l'exécution.

func Sum[T int | float64](a, b T) T {
    return a + b
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Les génériques éliminent le risque de panique d'exécution causée par des assertions de type incorrectes et améliorent la clarté.

Performance

Les génériques produisent du code spécialisé pour chaque type, conduisant à de meilleures performances d'exécution par rapport à l'interface{}.

Taille binaire

Un compromis existe : les génériques augmentent la taille des binaires en raison de la duplication de code pour chaque type, mais cela est souvent négligeable par rapport aux avantages.

Limites des génériques Go

Complexité des contraintes : Même si les contraintes ressemblent à des contraintes.Ordonnées, elles simplifient les cas d'utilisation courants, la définition de contraintes hautement personnalisées peut devenir verbeuse.

Aucune inférence de type dans les structures : Contrairement aux fonctions, vous devez spécifier explicitement le paramètre de type pour les structures.

func PrintValues[T any](values []T) {
    for _, v := range values {
        fmt.Println(v)
    }
}
Copier après la connexion
Copier après la connexion

Limité aux contraintes de temps de compilation : Les génériques Go se concentrent sur la sécurité au moment de la compilation, tandis que des langages comme Rust offrent des contraintes plus puissantes utilisant des durées de vie et des traits.

Faisons un benchmark – Mieux fait que dit

Nous allons implémenter une file d'attente simple avec à la fois une interface{} et générique et comparer les résultats.

Interface{} Implémentation de la file d'attente

func CheckDuplicates[T comparable](items []T) []T {
    seen := make(map[T]bool)
    duplicates := []T{}
    for _, item := range items {
        if seen[item] {
            duplicates = append(duplicates, item)
        } else {
            seen[item] = true
        }
    }
    return duplicates
}
Copier après la connexion
Copier après la connexion

Implémentation de file d'attente générique

import (
     "golang.org/x/exp/constraints"
     "fmt"
)

func SortSlice[T constraints.Ordered](items []T) []T {
    sorted := append([]T{}, items...) // Copy slice
    sort.Slice(sorted, func(i, j int) bool {
        return sorted[i] < sorted[j]
    })
    return sorted
}

func main() {
    nums := []int{5, 2, 9, 1}
    fmt.Println(SortSlice(nums)) // Output: [1 2 5 9]

    words := []string{"banana", "apple", "cherry"}
    fmt.Println(SortSlice(words)) // Output: [apple banana cherry]
}
Copier après la connexion
Copier après la connexion
type Numeric interface {
    int | float64 | uint
}
Copier après la connexion
Copier après la connexion

Analyse des résultats

  • Durée d'exécution :
    L'implémentation générique est environ 63,64 % plus rapide que la version interface{} car elle évite les assertions de type d'exécution et fonctionne directement sur le type donné.

  • Allocations :
    La version interface{} effectue 3 fois plus d'allocations, principalement en raison du boxing/unboxing lors de l'insertion et de la récupération de valeurs. Cela ajoute des frais généraux à la collecte des ordures.

Pour les charges de travail plus importantes, telles qu'un million d'opérations de mise en file d'attente/retrait de la file d'attente, l'écart de performances se creuse. Les applications du monde réel ayant des exigences de débit élevé (par exemple, files d'attente de messages, planificateurs de tâches) bénéficient considérablement des génériques.

Pensées finales

Generics in Go établit un équilibre entre puissance et simplicité et offre une solution pratique pour écrire du code réutilisable et sécurisé. Bien qu'il ne soit pas aussi riche en fonctionnalités que Rust ou C, il s'aligne parfaitement sur la philosophie minimaliste de Go. Comprendre les contraintes telles que les contraintes. Commander et exploiter efficacement les génériques peut grandement améliorer la qualité et la maintenabilité du code.

À mesure que les génériques continuent d’évoluer, ils sont destinés à jouer un rôle central dans l’écosystème de Go. Alors plongez, expérimentez et adoptez la nouvelle ère de sécurité des types et de flexibilité dans la programmation Go !

Consultez le référentiel github pour quelques exemples sur les génériques.

GitHub logo sadananddodawadakar / AllerGénériques

Le référentiel contient des exemples fonctionnels de génériques go

Go Generics : référentiel d'exemples complet

Bienvenue dans le Référentiel Go Generics ! Ce référentiel est une ressource unique pour comprendre, apprendre et maîtriser les génériques dans Go, introduits dans la version 1.18. Les génériques apportent la puissance des paramètres de type à Go, permettant aux développeurs d'écrire du code réutilisable et sécurisé sans compromettre les performances ou la lisibilité.

Ce référentiel contient des exemples soigneusement sélectionnés qui couvrent un large éventail de sujets, de la syntaxe de base aux modèles avancés et aux cas d'utilisation pratiques. Que vous soyez un développeur Go débutant ou expérimenté, cette collection vous aidera à exploiter efficacement les génériques dans vos projets.


? Qu'y a-t-il à l'intérieur

? Programmes génériques de base

Ces exemples présentent les concepts fondamentaux des génériques, vous aidant à comprendre la syntaxe et les fonctionnalités principales :

  1. GenericMap : démontre une fonction de carte générique pour transformer des tranches de tout type.
  2. Swap : Un exemple simple mais puissant d'échange générique de deux valeurs.
  3. FilterSlice : montre comment filtrer…


Voir sur GitHub


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

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

<🎜>: Grow A Garden - Guide de mutation complet
3 Il y a quelques semaines By DDD
<🎜>: Bubble Gum Simulator Infinity - Comment obtenir et utiliser les clés royales
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers of the Witch Tree - Comment déverrouiller le grappin
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Système de fusion, expliqué
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Tutoriel Java
1668
14
Tutoriel PHP
1273
29
Tutoriel C#
1256
24
Golang vs Python: performance et évolutivité Golang vs Python: performance et évolutivité Apr 19, 2025 am 12:18 AM

Golang est meilleur que Python en termes de performances et d'évolutivité. 1) Les caractéristiques de type compilation de Golang et le modèle de concurrence efficace le font bien fonctionner dans des scénarios de concurrence élevés. 2) Python, en tant que langue interprétée, s'exécute lentement, mais peut optimiser les performances via des outils tels que Cython.

Golang et C: concurrence vs vitesse brute Golang et C: concurrence vs vitesse brute Apr 21, 2025 am 12:16 AM

Golang est meilleur que C en concurrence, tandis que C est meilleur que Golang en vitesse brute. 1) Golang obtient une concurrence efficace par le goroutine et le canal, ce qui convient à la gestion d'un grand nombre de tâches simultanées. 2) C Grâce à l'optimisation du compilateur et à la bibliothèque standard, il offre des performances élevées près du matériel, adaptées aux applications qui nécessitent une optimisation extrême.

Partage avec Go: un guide du débutant Partage avec Go: un guide du débutant Apr 26, 2025 am 12:21 AM

GOISIDEALFORBEGINNERNERS et combinant pour pourcloudandNetWorkServicesDuetOtssimplicity, Efficiency, andCurrencyFeatures.1) InstallgofromTheofficialwebsiteandverifywith'goversion'..2)

Golang vs C: Performance et comparaison de la vitesse Golang vs C: Performance et comparaison de la vitesse Apr 21, 2025 am 12:13 AM

Golang convient au développement rapide et aux scénarios simultanés, et C convient aux scénarios où des performances extrêmes et un contrôle de bas niveau sont nécessaires. 1) Golang améliore les performances grâce à des mécanismes de collecte et de concurrence des ordures, et convient au développement de services Web à haute concurrence. 2) C réalise les performances ultimes grâce à la gestion manuelle de la mémoire et à l'optimisation du compilateur, et convient au développement du système intégré.

Impact de Golang: vitesse, efficacité et simplicité Impact de Golang: vitesse, efficacité et simplicité Apr 14, 2025 am 12:11 AM

GOIMIMPACTSDEVENCEMENTSPOSITIVEMENTS INSPECT, EFFICACTION ET APPLICATION.1) VITESSE: GOCOMPILESQUICKLYANDRUNSEFFIÉMENT, IDEALFORLARGEPROROSTS.2) Efficacité: ITSCOMPEHENSIVESTANDARDLIBRARYREDUCEEXTERNEDENDENCES, EnhancingDevelovefficiency.3) Simplicité: Simplicité: Implicité de la manière

C et Golang: Lorsque les performances sont cruciales C et Golang: Lorsque les performances sont cruciales Apr 13, 2025 am 12:11 AM

C est plus adapté aux scénarios où le contrôle direct des ressources matérielles et une optimisation élevée de performances sont nécessaires, tandis que Golang est plus adapté aux scénarios où un développement rapide et un traitement de concurrence élevé sont nécessaires. 1.C's Avantage est dans ses caractéristiques matérielles proches et à des capacités d'optimisation élevées, qui conviennent aux besoins de haute performance tels que le développement de jeux. 2. L'avantage de Golang réside dans sa syntaxe concise et son soutien à la concurrence naturelle, qui convient au développement élevé de services de concurrence.

Golang vs Python: différences et similitudes clés Golang vs Python: différences et similitudes clés Apr 17, 2025 am 12:15 AM

Golang et Python ont chacun leurs propres avantages: Golang convient aux performances élevées et à la programmation simultanée, tandis que Python convient à la science des données et au développement Web. Golang est connu pour son modèle de concurrence et ses performances efficaces, tandis que Python est connu pour sa syntaxe concise et son écosystème de bibliothèque riche.

Golang et C: les compromis en performance Golang et C: les compromis en performance Apr 17, 2025 am 12:18 AM

Les différences de performance entre Golang et C se reflètent principalement dans la gestion de la mémoire, l'optimisation de la compilation et l'efficacité du temps d'exécution. 1) Le mécanisme de collecte des ordures de Golang est pratique mais peut affecter les performances, 2) la gestion manuelle de C et l'optimisation du compilateur sont plus efficaces dans l'informatique récursive.

See all articles