1 points par GN⁺ 2 시간 전 | 1 commentaires | Partager sur WhatsApp
  • Cette version améliore les littéraux de structures et l’inférence de types autour des méthodes génériques, et ajoute des fonctionnalités pratiques dans toute la bibliothèque standard, le runtime et la chaîne d’outils
  • L’allocation mémoire spécialisée par taille réduit jusqu’à 30 % le coût de certaines allocations de moins de 80 octets ; les programmes intensifs en allocations devraient gagner environ 1 % de performances, avec une augmentation du binaire d’environ 60 Ko
  • encoding/json/v2 est officiellement disponible, l’ancien encoding/json utilise aussi v2 en interne, et un package UUID standard ainsi que les signatures ML-DSA basées sur FIPS 204 sont ajoutés
  • Le profil goroutineleak, les labels pprof dans les tracebacks, synctest.Sleep pour le temps virtuel et les serveurs de test HTTP en mémoire facilitent le diagnostic et les tests de concurrence
  • Les canaux de timers non bufferisés, l’épuisement automatique des corps de réponses HTTP et le renforcement des restrictions de //go:linkname peuvent affecter le code existant : une vérification de compatibilité avant le passage à Go 1.27 est nécessaire

Langage et système de types

  • Les méthodes génériques, au cœur de Go 1.27, peuvent déclarer leurs propres paramètres de type indépendamment du receiver
    • Auparavant, seules les fonctions de premier niveau pouvaient être génériques, si bien que les opérations appartenant à un type devaient aussi être écrites comme fonctions de package
    • On peut définir sous forme de méthode une opération qui renvoie un type d’élément différent de celui de l’entrée, comme Box[T].Map[U]
    • Les interfaces ne peuvent toujours pas déclarer de méthodes à paramètres de type, et les méthodes génériques ne peuvent pas non plus implémenter des interfaces
  • Les clés de littéraux de structures peuvent utiliser non seulement des noms de champs de premier niveau, mais aussi des sélecteurs de champs valides
    • Les champs promus depuis une structure embarquée peuvent être initialisés directement, comme dans User{ID: 7}
  • L’inférence de types de fonctions est étendue aux conversions et aux littéraux composés
    • Comme dans []func([]int) int{first, last}, les arguments de type d’une fonction générique sont inférés à partir du type de fonction attendu
    • Auparavant, il fallait instancier explicitement, par exemple first[int] et last[int]

Runtime et performances

  • Le compilateur appelle des routines d’allocation spécialisées par taille qui réduisent jusqu’à 30 % le coût de certaines allocations mémoire de moins de 80 octets
    • Le gain global attendu dans les programmes réellement intensifs en allocations est d’environ 1 %
    • Aucune modification du code n’est nécessaire, mais le binaire grossit d’environ 60 Ko quelle que soit la charge de travail
    • Il est possible de désactiver cette option avec GOEXPERIMENT=nosizespecializedmalloc, mais ce choix sera supprimé dans Go 1.28
  • Trois optimisations du compilateur activées par défaut sont ajoutées
    • Une passe de flux de données known bits qui suit les bits dont on sait avec certitude qu’ils valent 0 ou 1 dans une valeur afin d’éliminer les opérations redondantes
    • Le déplacement hors des boucles des calculs qui ne changent pas pendant l’itération
    • La compilation des switch éligibles en tables de correspondance, y compris avec fallthrough
  • L’option expérimentale GOEXPERIMENT=mapsplitgroup change la disposition mémoire des groupes de maps de KVKVKVKV à KKKKVVVV ; elle est désactivée par défaut
  • Le linker déplace les descripteurs de types et les itab dans une section dédiée .go.type, et supprime typelinks et itablinks
    • Comme reflect.typelinks renvoie des types plutôt que des offsets, les bibliothèques qui accèdent à ce symbole via //go:linkname peuvent être affectées

Diagnostic des goroutines et profiling

  • Les modules dont go.mod indique Go 1.27 ou plus affichent les labels runtime/pprof dans l’en-tête de goroutine des tracebacks
    • Le contexte ajouté avec pprof.Do, comme {request: 42}, apparaît dans les crash dumps, SIGQUIT et la sortie de runtime.Stack
    • Pour éviter l’exposition de labels sensibles dans les tracebacks, GODEBUG=tracebacklabels=0 reste disponible
  • Le détecteur de fuites de goroutines, fonctionnalité expérimentale de Go 1.26, devient un profil officiel goroutineleak
    • Il lance le GC pour trouver les goroutines qui ne pourront jamais progresser, par exemple sur des channels ou des mutex, et affiche leurs piles
    • Dans les services, il peut être collecté via l’endpoint /debug/pprof/goroutineleak, sans nécessiter GOEXPERIMENT

Cryptographie et identifiants

  • Le nouveau package crypto/mldsa implémente les signatures post-quantiques ML-DSA de FIPS 204
    • Les trois ensembles de paramètres MLDSA44, MLDSA65 et MLDSA87 arbitrent entre taille des clés, taille des signatures et niveau de sécurité
    • ML-DSA est également ajouté aux clés et signatures de crypto/x509, ainsi qu’aux modes de signature TLS 1.3 de crypto/tls
  • Le nouveau package uuid de la bibliothèque standard génère et parse des UUID RFC 9562 à partir de nombres aléatoires cryptographiquement sûrs
    • uuid.New() choisit une méthode adaptée aux usages courants, NewV4() produit un UUID purement aléatoire et NewV7() un UUID ordonné par date de création
    • Les UUID construits à partir d’aléa sont comparables, ce qui permet d’utiliser directement ==
    • Les UUID v7, triables chronologiquement, conviennent bien comme clés de bases de données

JSON et API de traitement de données

  • encoding/json/v2 et le bas niveau encoding/json/jsontext sont disponibles sans GOEXPERIMENT=jsonv2
    • L’ancien encoding/json v1 utilise aussi en interne l’implémentation v2
    • Le comportement existant est conservé, hormis quelques formulations de messages d’erreur ; aucune migration n’est donc nécessaire
    • En cas de problème de compatibilité, GOEXPERIMENT=nojsonv2 permet de restaurer l’implémentation v1 d’origine
    • Pour des raisons de performance, v2 ne trie pas les clés de map par défaut ; dans les tests nécessitant une sortie stable, il faut spécifier json.Deterministic
  • strings.CutLast et bytes.CutLast découpent une valeur selon le dernier séparateur
    • Si le séparateur est absent, ils renvoient toute l’entrée, une seconde partie vide et false
  • Le Hasher[T] générique de hash/maphash définit à la fois la stratégie de hachage et d’égalité d’une valeur
    • Des valeurs égales doivent impérativement avoir le même hash
    • ComparableHasher[T] est fourni pour les types comparables, et il est aussi possible d’implémenter des stratégies personnalisées, par exemple pour des chaînes insensibles à la casse
  • math/big.Int.Divide calcule quotient et reste ensemble en appliquant explicitement un mode d’arrondi parmi Trunc, Floor, Round et Ceil
    • Le reste varie aussi selon le mode d’arrondi, ce qui compense dans le code financier et numérique les limites de la troncature vers zéro de Quo et Mod
  • math/rand/v2.(*Rand).N génère, depuis sa propre source *Rand, un nombre aléatoire borné pour les types entiers ou duration

SIMD portable

  • Le package expérimental simd fournit une API SIMD indépendante de la taille des vecteurs et s’active avec GOEXPERIMENT=simd
    • Sur les environnements pris en charge, il compile vers de véritables instructions vectorielles matérielles ; sinon, il bascule vers une émulation en Go pur
    • Le nombre de lanes de types comme Float32s n’est pas fixe et suit la largeur matérielle de la machine
  • La bibliothèque standard utilise déjà en interne les intrinsics simd/archsimd
    • MemHash32, MemHash64 et StrHash des maps Swiss Table sont réimplémentés sur cette nouvelle base SIMD

Tests déterministes

  • testing/synctest.Sleep fait avancer le temps virtuel et attend que toutes les goroutines soient stabilisées en une seule opération
    • Dans une bulle synctest, le temps réel ne s’écoule pas : une attente de 2 secondes se termine immédiatement
    • Il remplace le code répétitif combinant auparavant time.Sleep et synctest.Wait
  • httptest.NewTestServer exécute un serveur sur un réseau virtuel en mémoire au lieu d’utiliser un vrai port TCP
    • srv.Client() se connecte directement au handler via un pipe interne au processus
    • Le nettoyage étant automatique via t.Cleanup, defer srv.Close() n’est plus nécessaire
    • Combiné à testing/synctest, il permet de tester rapidement et de façon déterministe les allers-retours HTTP en temps virtuel

Réseau et changements de compatibilité

  • Les channels renvoyés par time.After, time.NewTimer, time.NewTicker, etc. deviennent toujours des channels synchrones non bufferisés
    • Le paramètre GODEBUG asynctimerchan, qui restaurait l’ancien comportement bufferisé, est supprimé
  • En HTTP/1, http.Response.Body.Close lit le corps non consommé jusqu’à une limite prudente afin de faciliter la réutilisation de la connexion
    • Si vous comptiez sur Close pour interrompre prématurément un gros téléchargement, il faut désactiver la réutilisation avec Transport.DisableKeepAlives
  • Les serveurs HTTP/2 comprennent les priorités client de la RFC 9218 et traitent d’abord les streams à haute priorité
    • Server.DisableClientPriority = true permet de restaurer l’ancien comportement round-robin
  • Sous Windows et macOS, crypto/x509.SystemCertPool prend en charge SSL_CERT_FILE et SSL_CERT_DIR
    • Si les variables sont définies, les certificats racines sont lus depuis le disque et le vérificateur Go est utilisé à la place des API de la plateforme
    • Cela peut être désactivé avec GODEBUG=x509sslcertoverrideplatform=0
  • L’implémentation HTTP/2 auparavant incluse dans le fichier généré h2_bundle.go de 12 226 lignes est remplacée par un vrai package net/http/internal/http2
  • net/http ajoute des hooks HTTP/3 enfichables avant exposition publique, et une partie de la suite de tests s’exécute en HTTP/3
    • Il n’existe pas encore d’API publique appelable, mais les bases d’un futur http.Transport basé sur QUIC sont incluses

Chaîne d’outils

  • go test exécute par défaut la vérification vet stdversion, qui détecte l’utilisation de symboles de la bibliothèque standard plus récents que la version de Go déclarée dans go.mod
  • go doc pkg@version permet de consulter la documentation d’une version précise d’un module
  • go doc -ex liste les exemples exécutables, et affiche le source quand on indique directement le nom d’un exemple
  • go fix ajoute les analyseurs de modernisation atomictypes, embedlit, slicesbackward et unsafefuncs
    • waitgroup est renommé en waitgroupgo et fmtappendf est supprimé
  • Dans les modules Go 1.27 ou plus, go mod tidy fusionne les blocs require dispersés en deux blocs pour dépendances directes et indirectes, tout en conservant les commentaires
  • go tool trace -http=:6060 ne se lie qu’à localhost si seul un port est fourni ; pour un accès externe, il faut spécifier l’adresse
  • La commande go supprime la prise en charge du système de gestion de versions Bazaar (bzr)
  • compile, link, asm, cgo, cover et pack prennent en charge les fichiers de réponse (@file) au format GCC afin de contourner les limites de longueur de ligne de commande

Unicode et périmètre de sécurité

  • Les données Unicode de la bibliothèque standard passent de Unicode 15 à Unicode 17
    • Les caractères ajoutés dans Unicode 16 sont eux aussi correctement classés comme symboles et caractères imprimables
  • Un problème permettant de sortir de la racine via os.Root.ReadDir et Readdir est corrigé
  • L’utilisation non approuvée de //go:linkname devient plus difficile
    • La directive linknamestd marque les linknames importables uniquement par la bibliothèque standard
    • Le linker vérifiant aussi l’accès par linkname aux symboles d’assembly, le code dépendant de symboles internes non officiels doit être testé tôt

1 commentaires

 
GN⁺ 2 시간 전
Avis sur Lobste.rs
  • Peut-être la meilleure version à ce jour. SIMD, uuid, jsonv2 arrivent enfin

    • Il faudrait aussi prendre en charge UUID v5 pour pouvoir migrer complètement
  • C’est un peu hors sujet, mais c’est un bon exemple des bugs qui apparaissent quand on traite tout comme une chaîne sans tenir compte du contrat et des liens entre les méthodes d’une interface
    Equal ignore la casse, mais Hash utilise la valeur convertie en minuscules. Or EqualFold et ToLower ne définissent pas la même relation d’équivalence
    https://github.com/golang/go/issues/52204
    "\u017F" (ſ, s long) et "s" sont égaux avec EqualFold, mais leurs résultats respectifs après ToLower diffèrent. Donc, si l’on insère "s" puis "ſ", le hachage est différent et l’élément est inséré séparément
    Le plus amusant, c’est que la documentation met justement en garde contre ce cas
    https://github.com/golang/go/…

  • Content que quelqu’un ait repris là où Anton s’était arrêté

    • Malheureusement, au moins une partie, en particulier la section sur l’utilisation de JSON v2 par défaut, semble avoir été écrite avec un LLM. Je n’aime pas le style, mais le contenu reste intéressant
    • Il ne semble pas qu’Anton ait arrêté. Il a aussi écrit sur 1.26, donc il semble plutôt que cet article ait été publié en premier par quelqu’un d’autre
  • J’aime Go, mais je me demande si la syntaxe de Go est assez élégante pour continuer à ajouter ce genre de fonctionnalités à chaque version
    func (b Box[T]) Map[U any](f func(T) U) Box[U] {

    • C’est subjectif, mais je ne la trouve pas pire que celle d’autres langages prenant en charge cette fonctionnalité. Zig est le plus proche, tandis que Rust, TypeScript et C++20 utilisent généralement le type comme conteneur pour les définitions de méthodes, ce qui réduit le coût de répétition du type receveur dans plusieurs méthodes
      À l’inverse, la verbosité de Go et de Zig a l’avantage de ne pas obliger à faire défiler ailleurs pour retrouver la définition du receveur. Aux sites d’appel, que l’on peut considérer comme plus importants que les définitions, tout se ressemble à peu près et il n’est pas non plus nécessaire de préciser les types
  • J’ai quitté Go pendant un moment, mais jsonv2 m’intéresse. Cela dit, s’il devient la valeur par défaut, je me demande si Go ne rompt pas la promesse de compatibilité qu’il tient depuis longtemps

    • jsonv2 doit être importé depuis un chemin séparé, encoding/json/v2, donc il faut le choisir explicitement. L’ancien encoding/json utilise v2 en interne, mais garantit le comportement précédent, et jsonv2 fournit aussi des options pour reproduire les comportements exceptionnels de v1, donc cela ne rompt pas la promesse de compatibilité
    • J’utilise la bibliothèque jsontext de v2 dans un projet Go 1.26 et j’en suis très satisfait