La dernière version de Go, la version 1.21, arrive six mois après Go 1.20. La plupart des changements concernent l'implémentation de la chaîne d'outils, du moteur d'exécution et des bibliothèques. Comme toujours, la version maintient la promesse de compatibilité de Go 1 ; en fait, Go 1.21 améliore cette promesse. Nous nous attendons à ce que presque tous les programmes Go continuent à se compiler et à s'exécuter comme auparavant.
Go 1.21 introduit un petit changement dans la numérotation des versions. Par le passé, nous utilisions Go 1.N pour désigner à la fois la version globale du langage Go et la famille de versions, ainsi que la première version de cette famille. À partir de Go 1.21, la première version est désormais Go 1.N.0. Aujourd'hui, nous publions à la fois le langage Go 1.21 et son implémentation initiale, la version Go 1.21.0. Ces notes font référence à "Go 1.21" ; des outils comme go version indiqueront "go1.21.0" (jusqu'à ce que vous passiez à Go 1.21.1). Voir "Go versions" dans la documentation "Go Toolchains" pour plus de détails sur la nouvelle numérotation des versions.
Changements dans le langage
Go 1.21 ajoute trois nouvelles fonctions au langage :
- Les nouvelles fonctions min et max calculent la plus petite (ou la plus grande, pour max) valeur d'un nombre fixe d'arguments donnés.
- La nouvelle fonction clear supprime tous les éléments d'une carte ou met à zéro tous les éléments d'une tranche.
L'ordre d'initialisation des paquets est maintenant spécifié plus précisément. Le nouvel algorithme est le suivant :
- Trier tous les paquets par chemin d'importation.
- Répéter jusqu'à ce que la liste des paquets soit vide :
- Trouver le premier paquet de la liste pour lequel toutes les importations sont déjà initialisées.
- Initialiser ce paquet et le supprimer de la liste.
Cela peut modifier le comportement de certains programmes qui s'appuient sur un ordre d'initialisation spécifique qui n'a pas été exprimé par des importations explicites. Le comportement de ces programmes n'était pas bien défini par la spécification dans les versions précédentes. La nouvelle règle fournit une définition sans ambiguïté.
De nombreuses améliorations qui augmentent la puissance et la précision de l'inférence de type ont été apportées.
- Une fonction (éventuellement générique partiellement instanciée) peut désormais être appelée avec des arguments qui sont eux-mêmes des fonctions génériques (éventuellement partiellement instanciées). Le compilateur tentera de déduire les arguments de type manquants de l'appelé (comme auparavant) et, pour chaque argument qui est une fonction générique qui n'est pas entièrement instanciée, ses arguments de type manquants (nouveau). Les cas d'utilisation typiques sont les appels à des fonctions génériques opérant sur des conteneurs (telles que slices.IndexFunc) où un argument de fonction peut également être générique et où le type d'argument de la fonction appelée et ses arguments sont déduits du type de conteneur. Plus généralement, une fonction générique peut désormais être utilisée sans instanciation explicite lorsqu'elle est affectée à une variable ou renvoyée comme valeur de résultat si les arguments de type peuvent être déduits de l'affectation.
- L'inférence de type prend désormais également en compte les méthodes lorsqu'une valeur est assignée à une interface : les arguments de type pour les paramètres de type utilisés dans les signatures de méthode peuvent être déduits des types de paramètres correspondants des méthodes correspondantes.
- De même, étant donné qu'un argument de type doit implémenter toutes les méthodes de sa contrainte correspondante, les méthodes de l'argument de type et de la contrainte sont mises en correspondance, ce qui peut conduire à l'inférence d'arguments de type supplémentaires.
- Si plusieurs arguments constants non typés de types différents (tels qu'un int non typés et une constante flottante non typée) sont passés à des paramètres ayant le même type de paramètre (non spécifié par ailleurs), au lieu d'une erreur, l'inférence de type détermine maintenant le type en utilisant la même approche qu'un opérateur avec des opérandes constants non typés. Cette modification permet d'aligner les types déduits des arguments constants non typés sur les types des expressions constantes.
- L'inférence de type est désormais précise lorsqu'il s'agit de faire correspondre des types dans des affectations : les types des composants (tels que les éléments des tranches ou les types des paramètres dans les signatures de fonctions) doivent être identiques (avec des arguments de type appropriés) pour correspondre, sinon l'inférence échoue. Cette modification produit des messages d'erreur plus précis : là où, par le passé, l'inférence de type pouvait réussir de manière incorrecte et conduire à une affectation invalide, le compilateur signale désormais une erreur d'inférence si deux types ne peuvent pas correspondre.
Plus généralement, la description de l'inférence de type dans la spécification du langage a été clarifiée. L'ensemble de ces changements rend l'inférence de type plus puissante et les échecs d'inférence moins surprenants.
Go 1.21 inclut un aperçu d'un changement de langage que nous envisageons pour une future version de Go : rendre les variables de boucle par itération au lieu de par boucle, pour éviter les bogues de partage accidentel.
Go 1.21 définit maintenant que si une goroutine panique et que recover a été appelée directement par une fonction différée, la valeur de retour de recover est garantie comme n'étant pas nulle. Pour s'en assurer, appeler panic avec une valeur d'interface nulle (ou un nil non typé) provoque une panique à l'exécution de type *runtime.PanicNilError.
Pour supporter les programmes écrits pour des versions plus anciennes de Go, les paniques nil peuvent être réactivées en mettant GODEBUG=panicnil=1. Ce paramètre est activé automatiquement lors de la compilation d'un programme dont le package principal se trouve dans un module qui déclare go 1.20 ou une version antérieure.
Outils
Go 1.21 ajoute un support amélioré pour la compatibilité ascendante et descendante dans la chaîne d'outils Go.
Pour améliorer la rétrocompatibilité, Go 1.21 formalise l'utilisation par Go de la variable d'environnement GODEBUG pour contrôler le comportement par défaut pour les changements qui ne sont pas cassants selon la politique de compatibilité, mais qui peuvent néanmoins causer des cassures dans les programmes existants. (Par exemple, les programmes qui dépendent d'un comportement bogué peuvent se casser quand un bogue est corrigé, mais les corrections de bogues ne sont pas considérées comme des changements qui cassent). Lorsque Go doit effectuer ce type de changement de comportement, il choisit maintenant entre l'ancien et le nouveau comportement en se basant sur la ligne go dans le fichier go.work de l'espace de travail ou dans le fichier go.mod du module principal. La mise à jour vers une nouvelle chaîne d'outils Go tout en laissant la ligne go à sa version Go originale (plus ancienne) préserve le comportement de l'ancienne chaîne d'outils. Grâce à ce support de compatibilité, la dernière chaîne d'outils Go devrait toujours être la meilleure implémentation, la plus sûre, d'une ancienne version de Go.
Pour améliorer la compatibilité ascendante, Go 1.21 lit maintenant la ligne go dans un fichier go.work ou go.mod comme une exigence minimale stricte : go 1.21.0 signifie que l'espace de travail ou le module ne peut pas être utilisé avec Go 1.20 ou avec Go 1.21rc1. Cela permet aux projets qui dépendent des corrections apportées dans les versions ultérieures de Go de s'assurer qu'ils ne sont pas utilisés avec des versions antérieures. Cela permet également de mieux signaler les erreurs pour les projets qui utilisent de nouvelles fonctionnalités de Go : lorsque le problème est qu'une version plus récente de Go est nécessaire, ce problème est clairement signalé, au lieu d'essayer de construire le code et d'afficher des erreurs concernant des importations non résolues ou des erreurs de syntaxe.
Pour faciliter la gestion de ces nouvelles exigences plus strictes en matière de versions, la commande go peut désormais invoquer non seulement la chaîne d'outils fournie dans sa propre version, mais aussi d'autres versions de la chaîne d'outils Go trouvées dans le PATH ou téléchargées à la demande. Si une ligne de go.mod ou go.work déclare une exigence minimale pour une version plus récente de Go, la commande go trouvera et exécutera cette version automatiquement. La directive new toolchain définit une chaîne d'outils minimale suggérée à utiliser, qui peut être plus récente que la chaîne minimale stricte de Go.
Commande Go
L'option de construction -pgo est maintenant définie par défaut sur -pgo=auto, et la restriction de spécifier un seul paquetage principal sur la ligne de commande est maintenant supprimée. Si un fichier nommé default.pgo est présent dans le répertoire du paquetage principal, la commande go l'utilisera pour activer l'optimisation guidée par le profil pour la construction du programme correspondant.
L'option -C dir doit maintenant être la première option de la ligne de commande lorsqu'elle est utilisée.
La nouvelle option go test -fullpath imprime les noms de chemin complets dans les messages du journal de test, plutôt que les noms de base.
L'option go test -c permet désormais d'écrire des binaires de test pour plusieurs paquetages, chacun dans pkg.test où pkg est le nom du paquetage. C'est une erreur si plus d'un paquetage de test en cours de compilation a un nom de paquetage donné].
L'option go test -o accepte désormais un argument de répertoire, auquel cas les binaires de test sont écrits dans ce répertoire au lieu du répertoire courant.
Cgo
Dans les fichiers qui importent "C", la chaîne d'outils Go rapporte maintenant correctement les erreurs pour les tentatives de déclaration de méthodes Go sur des types C.
Runtime
Lors de l'impression de piles très profondes, le runtime imprime désormais les 50 premières images (les plus internes) suivies des 50 dernières images (les plus externes), plutôt que d'imprimer uniquement les 100 premières images. Cela permet de voir plus facilement à quelle profondeur les piles récursives ont commencé, et est particulièrement utile pour déboguer les débordements de pile.
Sur les plateformes Linux qui supportent les pages énormes transparentes, le runtime Go gère maintenant plus explicitement les parties du tas qui peuvent être soutenues par des pages énormes. Cela conduit à une meilleure utilisation de la mémoire : les petits tas devraient voir moins de mémoire utilisée (jusqu'à 50% dans les cas pathologiques) tandis que les grands tas devraient voir moins de pages énormes cassées pour les parties denses du tas, améliorant l'utilisation du CPU et la latence jusqu'à 1%.
Grâce à l'optimisation du ramassage des ordures interne à l'exécution, les applications peuvent voir leur temps de latence réduit de 40 % et leur utilisation de la mémoire légèrement diminuée. Certaines applications peuvent également observer une légère perte de débit. La diminution de l'utilisation de la mémoire devrait être proportionnelle à la perte de débit, de sorte que le compromis débit/mémoire de la version précédente peut être rétabli (avec peu de changement au niveau de la latence) en augmentant légèrement GOGC et/ou GOMEMLIMIT.
Les appels de C à Go sur des threads créés en C nécessitent une certaine configuration pour préparer l'exécution de Go. Sur les plates-formes Unix, cette préparation est désormais préservée pour plusieurs appels à partir du même thread. Cela permet de réduire de manière significative l'overhead des appels C to Go ultérieurs de ~1-3 microsecondes par appel à ~100-200 nanosecondes par appel.
Compilateur
L'optimisation par guide de profil (PGO), ajoutée en avant-première dans Go 1.20, est maintenant prête pour une utilisation générale. PGO permet des optimisations supplémentaires sur le code identifié comme chaud par les profils des charges de travail de production. Comme indiqué dans la section sur les commandes Go, PGO est activé par défaut pour les binaires qui contiennent un profil default.pgo dans le répertoire principal du paquetage. Les améliorations de performance varient en fonction du comportement de l'application, la plupart des programmes d'un ensemble représentatif de programmes Go voyant entre 2 et 7% d'amélioration grâce à l'activation de PGO.
Les constructions PGO peuvent maintenant dévirtualiser certains appels de méthodes d'interface, en ajoutant un appel concret à l'appelant le plus courant. Cela permet une optimisation plus poussée, comme la mise en ligne de l'appel.
Go 1.21 améliore la vitesse de compilation jusqu'à 6%, en grande partie grâce à la construction du compilateur lui-même avec PGO.
Assembleur
Sur amd64, les fonctions d'assemblage nosplit sans cadre ne sont plus automatiquement marquées comme NOFRAME. Au lieu de cela, l'attribut NOFRAME doit être explicitement spécifié si nécessaire, ce qui est déjà le cas sur d'autres architectures supportant les pointeurs de cadre. Ainsi, le moteur d'exécution maintient désormais les pointeurs de cadre pour les transitions de pile.
Le vérificateur qui vérifie les utilisations incorrectes de R15 lors de l'édition de liens dynamiques sur amd64 a été amélioré.
Éditeur de liens
Sur windows/amd64, l'éditeur de liens (avec l'aide du compilateur) émet maintenant par défaut les données de déroulement SEH, ce qui améliore l'intégration des applications Go avec les débogueurs Windows et d'autres outils.
Dans Go 1.21, l'éditeur de liens (avec l'aide du compilateur) est maintenant capable de supprimer les variables globales mortes (non référencées), si le nombre d'entrées dans l'initialisateur de la variable est suffisamment grand, et si les expressions de l'initialisateur sont exemptes d'effets de bord.
Bibliothèque principale
Nouveau paquetage log/slog
Le nouveau paquetage log/slog fournit une journalisation structurée avec des niveaux. La journalisation structurée émet des paires clé-valeur pour permettre un traitement rapide et précis de grandes quantités de données de journalisation. Ce paquetage permet l'intégration avec les outils et services d'analyse de logs les plus répandus.
Nouveau paquetage testing/slogtest
Le nouveau package testing/slogtest permet de valider les implémentations de slog.Handler.
Nouveau paquetage slices
Le nouveau package slices fournit de nombreuses opérations courantes sur les slices, en utilisant des fonctions génériques qui fonctionnent avec des slices de n'importe quel type d'élément.
Nouveau package maps
Le nouveau package maps fournit plusieurs opérations courantes sur les maps, en utilisant des fonctions génériques qui fonctionnent avec des maps de n'importe quel type de clé ou d'élément.
Nouveau paquetage cmp
Le nouveau package cmp définit la contrainte de type Ordered et deux nouvelles fonctions génériques Less et Compare qui sont utiles avec les types ordonnés.
Source : Go
Et vous ?
Qu'en pensez-vous ?
Voir aussi :
Go 1.20 est la dernière version qui fonctionnera sur toutes les versions de Windows 7, 8, Server 2008 et Server 2012, la version 1.21 nécessitera au moins Windows 10 ou Server 2016
Go 1.20 est disponible avec la prise en charge initiale de PGO et le support expérimental de FreeBSD sur RISC-V, et est la dernière version supportant Windows 7 / 8 / Server 2008 / Server 2012
La première release candidate de Go 1.21, le langage de programmation Open Source, est disponible, et apporte plusieurs nouvelles fonctionnalités, dont la prise en charge de PGO