1 puntos por GN⁺ 2 시간 전 | 1 comentarios | Compartir por WhatsApp
  • Esta versión se centra en métodos genéricos, mejora los literales de structs y la inferencia de tipos, y agrega funciones prácticas en toda la biblioteca estándar, el runtime y la toolchain
  • La asignación de memoria especializada por tamaño reduce hasta un 30% el costo de algunas asignaciones de menos de 80 bytes; en programas intensivos en asignaciones se espera una mejora de rendimiento de alrededor del 1% y un aumento del binario de unos 60 KB
  • encoding/json/v2 queda disponible oficialmente y el encoding/json existente también usa v2 internamente; se agregan un paquete UUID estándar y firmas ML-DSA basadas en FIPS 204
  • El perfil goroutineleak, las etiquetas pprof en tracebacks, synctest.Sleep para tiempo virtual y un servidor HTTP de pruebas en memoria facilitan el diagnóstico y las pruebas de concurrencia
  • El cambio de los canales de timers a no bufferizados, el agotamiento automático del cuerpo de respuestas HTTP y el endurecimiento de las restricciones de //go:linkname pueden afectar código existente, por lo que se necesita una verificación de compatibilidad antes de migrar a Go 1.27

Lenguaje y sistema de tipos

  • Los métodos genéricos, eje central de Go 1.27, pueden declarar sus propios parámetros de tipo independientes del receiver
    • Antes, solo las funciones de nivel superior podían ser genéricas, por lo que incluso las operaciones pertenecientes a un tipo debían escribirse como funciones de paquete
    • Operaciones como Box[T].Map[U], que devuelven un tipo de elemento distinto al de entrada, pueden definirse como métodos
    • Las interfaces todavía no pueden declarar métodos con parámetros de tipo, y tampoco se puede implementar una interfaz mediante métodos genéricos
  • En las claves de literales de structs se pueden usar selectores de campo válidos, no solo nombres de campos de nivel superior
    • En structs embebidos, los campos promovidos pueden inicializarse directamente, como User{ID: 7}
  • La inferencia de tipos de funciones se amplía a conversiones y literales compuestos
    • Infere los argumentos de tipo de funciones genéricas a partir del tipo de función esperado, como en []func([]int) int{first, last}
    • Antes era necesario instanciarlas directamente, como first[int] y last[int]

Runtime y rendimiento

  • El compilador llama a rutinas de asignación especializadas por tamaño para reducir hasta un 30% el costo de algunas asignaciones de memoria de menos de 80 bytes
    • En programas reales intensivos en asignaciones, se espera una mejora general de rendimiento de alrededor del 1%
    • No hace falta modificar el código, pero el binario crece unos 60 KB independientemente de la carga de trabajo
    • Puede desactivarse con GOEXPERIMENT=nosizespecializedmalloc, aunque esta opción se eliminará en Go 1.28
  • Se agregan tres optimizaciones del compilador habilitadas por defecto
    • Un pase de flujo de datos de known bits que rastrea bits que con certeza son 0 o 1 en un valor y elimina operaciones redundantes
    • Movimiento de código invariante de bucle, que saca del loop cálculos que no cambian durante la iteración
    • Compilación de switch que cumplan ciertas condiciones como tablas de búsqueda, incluyendo fallthrough
  • El experimento GOEXPERIMENT=mapsplitgroup cambia la disposición en memoria de los grupos de mapas de KVKVKVKV a KKKKVVVV, y está desactivado por defecto
  • El linker mueve los descriptores de tipo y los itab a una sección dedicada .go.type, y elimina typelinks e itablinks
    • Como reflect.typelinks devuelve tipos en lugar de offsets, pueden verse afectadas las bibliotecas que acceden a este símbolo mediante //go:linkname

Diagnóstico de goroutines y profiling

  • Los módulos cuyo go.mod indique Go 1.27 o posterior muestran etiquetas de runtime/pprof en el encabezado de goroutines de los tracebacks
    • Contextos agregados con pprof.Do, como {request: 42}, aparecen en volcados de fallos, SIGQUIT y salidas de runtime.Stack
    • Para evitar que etiquetas sensibles queden expuestas en tracebacks, se puede seguir usando GODEBUG=tracebacklabels=0
  • El detector de fugas de goroutines, que en Go 1.26 era experimental, pasa a ser el perfil oficial goroutineleak
    • Ejecuta el GC para encontrar goroutines que nunca podrán avanzar, por ejemplo en canales o mutexes, e imprime sus stacks
    • En servicios puede recopilarse mediante el endpoint /debug/pprof/goroutineleak, sin requerir GOEXPERIMENT

Criptografía e identificadores

  • El nuevo paquete crypto/mldsa implementa las firmas poscuánticas ML-DSA de FIPS 204
    • Los tres conjuntos de parámetros MLDSA44, MLDSA65 y MLDSA87 equilibran tamaño de claves y firmas con nivel de seguridad
    • También se agrega ML-DSA a claves y firmas de crypto/x509, y a los métodos de firma TLS 1.3 de crypto/tls
  • El nuevo paquete uuid de la biblioteca estándar genera y parsea UUID RFC 9562 con números aleatorios criptográficamente seguros
    • uuid.New() elige el método adecuado para usos generales; NewV4() crea UUID puramente aleatorios y NewV7() crea UUID ordenados por tiempo de generación
    • Los UUID basados en aleatoriedad son comparables, por lo que se puede usar == directamente
    • Los UUID v7, ordenables temporalmente, son adecuados como claves de base de datos

JSON y APIs de procesamiento de datos

  • encoding/json/v2 y el paquete de bajo nivel encoding/json/jsontext se ofrecen sin GOEXPERIMENT=jsonv2
    • El encoding/json v1 existente también usa internamente la implementación v2
    • Mantiene el comportamiento existente salvo por algunos textos de mensajes de error, por lo que no hace falta migrar
    • Si hay problemas de compatibilidad, se puede restaurar la implementación v1 original con GOEXPERIMENT=nojsonv2
    • Por rendimiento, v2 no ordena por defecto las claves de mapas, así que en pruebas que requieran salida estable debe especificarse json.Deterministic
  • strings.CutLast y bytes.CutLast dividen valores tomando como referencia el último separador
    • Si no hay separador, devuelven la entrada completa, una segunda parte vacía y false
  • El Hasher[T] genérico de hash/maphash define en conjunto la estrategia de hash e igualdad de los valores
    • Valores iguales deben tener siempre el mismo hash
    • Se ofrece ComparableHasher[T] para tipos comparables, y también se pueden implementar estrategias personalizadas, como strings sin distinguir mayúsculas y minúsculas
  • math/big.Int.Divide calcula cociente y resto juntos aplicando un modo de redondeo explícito entre Trunc, Floor, Round y Ceil
    • El resto también cambia según el modo de redondeo, lo que complementa en código financiero y numérico la limitación de truncamiento hacia cero de Quo y Mod existentes
  • math/rand/v2.(*Rand).N genera, desde su propia fuente *Rand, números aleatorios con límite de rango para tipos enteros o de duración

SIMD portable

  • El paquete experimental simd ofrece una API SIMD independiente del tamaño del vector y se habilita con GOEXPERIMENT=simd
    • En entornos compatibles compila a instrucciones vectoriales de hardware reales; de lo contrario, se reemplaza por emulación en Go puro
    • La cantidad de lanes de tipos como Float32s no es fija, sino que sigue el ancho de hardware de cada máquina
  • La biblioteca estándar ya usa intrínsecos internos de simd/archsimd
    • MemHash32, MemHash64 y StrHash de los mapas Swiss Table se reimplementaron sobre la nueva base SIMD

Pruebas deterministas

  • testing/synctest.Sleep avanza el tiempo virtual y espera a que todas las goroutines se estabilicen en una sola operación
    • Dentro de una burbuja synctest, el tiempo real no transcurre, por lo que una espera de 2 segundos termina al instante
    • Reemplaza el código repetitivo que combinaba time.Sleep y synctest.Wait
  • httptest.NewTestServer ejecuta un servidor sobre una red virtual en memoria en lugar de un puerto TCP real
    • srv.Client() se conecta directamente al handler mediante pipes dentro del proceso
    • Como se limpia automáticamente con t.Cleanup, no hace falta defer srv.Close()
    • Combinado con testing/synctest, incluso los viajes de ida y vuelta HTTP pueden probarse de forma rápida y determinista en tiempo virtual

Cambios de red y compatibilidad

  • Los canales devueltos por time.After, time.NewTimer, time.NewTicker y similares pasan a ser siempre canales síncronos sin buffer
    • Se elimina la opción GODEBUG asynctimerchan, que restauraba el comportamiento antiguo con buffer
  • En HTTP/1, http.Response.Body.Close lee el cuerpo no consumido hasta un límite conservador para ayudar a reutilizar la conexión
    • Si se dependía de Close para terminar anticipadamente una descarga grande, debe desactivarse la reutilización con Transport.DisableKeepAlives
  • Los servidores HTTP/2 entienden las prioridades de cliente de RFC 9218 y procesan primero los streams de mayor prioridad
    • Con Server.DisableClientPriority = true puede restaurarse el comportamiento round-robin anterior
  • crypto/x509.SystemCertPool en Windows y macOS soporta SSL_CERT_FILE y SSL_CERT_DIR
    • Si esas variables están configuradas, lee certificados raíz desde disco y usa el verificador de Go en lugar de la API de la plataforma
    • Puede desactivarse con GODEBUG=x509sslcertoverrideplatform=0
  • La implementación de HTTP/2 que antes estaba incluida en el archivo generado h2_bundle.go de 12,226 líneas se reemplaza por el paquete real net/http/internal/http2
  • En net/http se agregaron hooks enchufables de HTTP/3 previos a su exposición pública, y parte de la suite de pruebas se ejecuta sobre HTTP/3
    • Todavía no hay una API pública invocable, pero se incluye la base para un futuro http.Transport basado en QUIC

Toolchain

  • go test ejecuta por defecto la verificación vet stdversion, que detecta el uso de símbolos de la biblioteca estándar más nuevos que la versión de Go declarada en go.mod
  • Con go doc pkg@version se puede consultar la documentación de una versión específica de un módulo
  • go doc -ex lista ejemplos ejecutables y, si se especifica directamente el nombre de un ejemplo, imprime su fuente
  • A go fix se agregan los analizadores de modernización atomictypes, embedlit, slicesbackward y unsafefuncs
    • waitgroup cambia de nombre a waitgroupgo y fmtappendf se elimina
  • En módulos Go 1.27 o posteriores, go mod tidy combina bloques require dispersos en dos bloques para dependencias directas e indirectas, preservando comentarios
  • go tool trace -http=:6060, cuando solo recibe un puerto, se enlaza únicamente a localhost; para acceso externo debe indicarse una dirección
  • El comando go elimina el soporte para el sistema de control de versiones Bazaar (bzr)
  • compile, link, asm, cgo, cover y pack soportan archivos de respuesta (@file) al estilo GCC para evitar límites de longitud de la línea de comandos

Unicode y límites de seguridad

  • Los datos Unicode de la biblioteca estándar se actualizan de Unicode 15 a Unicode 17
    • Los caracteres agregados en Unicode 16 también se clasifican correctamente como símbolos y caracteres imprimibles
  • Se corrige un problema que permitía escapar fuera de la raíz usando os.Root.ReadDir y Readdir
  • Se vuelve más difícil el uso no autorizado de //go:linkname
    • La directiva linknamestd marca linknames que solo puede importar la biblioteca estándar
    • Como el linker también verifica el acceso mediante linkname a símbolos de ensamblador, el código que depende de símbolos internos no oficiales debe probarse con anticipación

1 comentarios

 
GN⁺ 2 시간 전
Opiniones en Lobste.rs
  • Quizás sea el mejor release de la historia. Por fin llegan SIMD, uuid, jsonv2

    • Parece que también debería soportar UUID v5 para poder migrar por completo
  • Aunque se sale un poco del tema, es un buen ejemplo de cómo aparecen bugs cuando se trata todo como string y no se considera el contrato ni la relación entre métodos de una interfaz
    Equal ignora mayúsculas y minúsculas, pero Hash usa el valor convertido a minúsculas. Sin embargo, EqualFold y ToLower no definen la misma relación de equivalencia
    https://github.com/golang/go/issues/52204
    "\u017F" (ſ, s larga) y "s" son iguales según EqualFold, pero los resultados de aplicar ToLower a cada uno son distintos. Por lo tanto, si insertas "s" y luego "ſ", el hash es distinto y se inserta como una entrada separada
    Lo más interesante es que la documentación advierte justamente sobre este caso
    https://github.com/golang/go/…

    • Para ser justos, la documentación dice claramente que son iguales según el criterio de plegado simple de mayúsculas/minúsculas de Unicode
      https://github.com/golang/go/…
  • Me alegra que otra persona haya retomado desde donde Anton se quedó

    • Lamentablemente, al menos algunas partes, en especial la sección sobre uso predeterminado de JSON v2, parecen escritas con un LLM. No me gusta el estilo, pero el contenido sigue siendo interesante
    • No parece que Anton lo haya dejado. También escribió el de 1.26, así que parece que esta vez otra persona publicó primero
  • Me gusta Go, pero me pregunto si la sintaxis de Go es lo suficientemente elegante como para seguir agregando este tipo de funciones en cada release
    func (b Box[T]) Map[U any](f func(T) U) Box[U] {

    • Es subjetivo, pero no diría que sea peor que otros lenguajes que soportan esta funcionalidad. Zig es el más parecido, y Rust, TypeScript y C++20 por lo general usan el tipo como contenedor de la definición de métodos, reduciendo el costo de repetir el tipo receptor en varios métodos
      En cambio, la verbosidad de Go y Zig tiene la ventaja de que no hace falta desplazarse a otro lugar para encontrar la definición del receptor. En el punto de llamada, que podría considerarse más importante que la definición, todos se ven casi iguales y tampoco hace falta especificar el tipo
  • Estuve alejado de Go por un tiempo y jsonv2 me entusiasma. Pero si pasa a ser el valor predeterminado, me pregunto si no rompe la promesa de compatibilidad que Go mantuvo durante tanto tiempo

    • jsonv2 debe importarse desde una ruta separada, encoding/json/v2, así que hay que elegirlo explícitamente. El encoding/json existente usa v2 internamente, pero garantiza el comportamiento anterior; además, jsonv2 incluye flags para reproducir comportamientos excepcionales de v1, por lo que no rompe la promesa de compatibilidad
    • En un proyecto con Go 1.26 estoy usando la biblioteca jsontext de v2 y estoy muy satisfecho