Go 1.22 se publicó el 6 de febrero de 2024 con cambios que, aunque pequeños individualmente, eliminan frustraciones que llevan años con el lenguaje: loop variable capture mejorado, HTTP ServeMux con routing pattern moderno, y rango sobre enteros. Los Go-ídiomas de 2024 son un poco más elegantes tras esta versión.
Este artículo cubre los cambios relevantes, cómo afectan código existente, y cómo migrar.
Loop variable scope: el fix histórico
El bug más famoso de Go (y más preguntado en Stack Overflow):
// Pre 1.22: comportamiento trampa
funcs := []func(){}
for _, i := range []int{1, 2, 3} {
funcs = append(funcs, func() { fmt.Println(i) })
}
for _, f := range funcs {
f()
}
// Output: 3 3 3 (no 1 2 3)
En 1.22, el mismo código funciona como esperas: imprime 1 2 3. La variable i ahora es re-declarada en cada iteración.
Esto arregla miles de bugs latentes en código Go antiguo, especialmente con goroutines y closures. Activado por defecto en 1.22 si tu go.mod tiene go 1.22.
Migración: algunos lugares donde dependías del comportamiento antiguo (raros pero existen) pueden romperse. Los errores suelen ser evidentes en tests.
HTTP ServeMux mejorado
El net/http.ServeMux ahora soporta patterns más expresivos sin necesitar libraries externas:
mux := http.NewServeMux()
// Method en el pattern
mux.HandleFunc("GET /users/{id}", userHandler)
mux.HandleFunc("POST /users", createUser)
mux.HandleFunc("DELETE /users/{id}", deleteUser)
// Wildcards
mux.HandleFunc("GET /static/", staticHandler)
// En handler, extraer path value
func userHandler(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
// ...
}
Patterns soportados:
- Method prefix:
GET,POST,PUT,DELETE, etc. - Wildcards:
{name}captura un segmento. - Trailing:
{rest...}captura el resto. - Host:
{host}/path.
Esto elimina la necesidad de gorilla/mux o chi para casos simples. Apps con routing básico pueden usar stdlib puro.
Rango sobre enteros
Sintaxis nueva para loops numéricos:
// Pre 1.22
for i := 0; i < 10; i++ {
// ...
}
// 1.22
for i := range 10 {
// ...
}
Sintáctico azúcar, pero más legible en muchos casos.
Toolchain management
Go 1.21 introdujo directiva toolchain, 1.22 madura:
// go.mod
go 1.22.0
toolchain go1.22.1
Go downloads automáticamente la toolchain específica si no está instalada. Evita “no tengo Go 1.22.1 en mi máquina”.
Mejoras de runtime
- Profiler menos intrusivo: overhead reducido en profiling.
- Garbage collector: tuning mejor para muchas goroutines.
- Memory allocator: mejoras para apps con muchas small allocations.
Números orientativos: 1-3% de mejora de performance típica vs 1.21, aunque varía por workload.
Math/rand/v2
Nueva versión del package random:
import "math/rand/v2"
// API más moderna
x := rand.IntN(100) // 0 to 99
f := rand.Float64()
Incompatible con math/rand (v1 sigue disponible). v2 tiene mejores generators (ChaCha8 por defecto).
Slog: ya estable
log/slog (structured logging) estable desde 1.21, mejoras en 1.22:
import "log/slog"
slog.Info("user login",
"user_id", 42,
"ip", "1.2.3.4",
"duration", time.Millisecond*150)
Reemplazo del log tradicional con structured logging built-in. Handlers JSON y text incluidos.
Vulnerability check
govulncheck integrada más profundamente:
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
Detecta vulnerabilidades conocidas en tus dependencias y en stdlib de tu Go version.
Changes que pueden romper
Lo que puede requerir atención:
- Loop variable scope: código que dependía del shared variable debe ajustarse.
GOEXPERIMENT=loopvaren 1.21 era opt-in; ahora es opt-out con flag de compatibilidad. - Algunos deprecations:
ioutiltotalmente depreciado (usaros+io). - Strictness en JSON: algunos edge cases de unmarshaling.
Normalmente go vet y tests atrapan estos.
Adopción del ecosistema
Al release:
- Kubernetes adoptó 1.22 rápido para 1.30.
- Docker upgrade natural.
- Gin, Echo, Fiber (web frameworks): compatibles, algunos añadieron soporte para el nuevo ServeMux routing en sus migrations docs.
- IDEs: GoLand, VSCode + gopls soportan 1.22 directamente.
Compatibilidad de API
Go mantiene compatibilidad backwards rigurosa. Código Go 1.0 sigue compilando en 1.22. Por eso las novedades son incrementales — nada se rompe sin flag.
Directiva go 1.22 en go.mod habilita nuevas semánticas; sin ella, comportamiento antiguo.
Actualizar: workflow
# Actualizar toolchain
go install golang.org/dl/go1.22.1@latest
go1.22.1 download
# Cambiar en go.mod
go mod edit -go=1.22.0
# Build y test
go build ./...
go test ./...
# Opcional: gofmt con -s para simplificaciones
gofmt -s -w .
Para la mayoría de proyectos, upgrade en una tarde.
Patrones nuevos
Con ServeMux mejorado, API REST básica en stdlib:
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /api/users", listUsers)
mux.HandleFunc("GET /api/users/{id}", getUser)
mux.HandleFunc("POST /api/users", createUser)
mux.HandleFunc("PUT /api/users/{id}", updateUser)
mux.HandleFunc("DELETE /api/users/{id}", deleteUser)
http.ListenAndServe(":8080", mux)
}
Para APIs pequeñas, no necesitas Gin/Echo. Para medianas/grandes, los frameworks siguen añadiendo valor (middleware, validation, etc).
El futuro: Go 1.23
Roadmap públicos menciona para 1.23:
- Iterators más potentes.
- Language tweaks menores.
- Performance continuous.
Go mantiene su filosofía: cambios lentos, retrocompatibles, pragmáticos.
Conclusión
Go 1.22 es release incremental pero muy valiosa. El fix de loop variables elimina un bug histórico que costaba horas de debugging. ServeMux mejorado reduce dependencia en libraries externas para casos comunes. El toolchain management facilita equipos con versiones heterogéneas. Actualizar es trivial para la mayoría de proyectos. Go sigue demostrando que iteración conservadora pero consistente es estrategia válida — código Go de 2024 es más expresivo sin perder la simplicidad que caracteriza al lenguaje.
Síguenos en jacar.es para más sobre Go, ecosistema backend y desarrollo idiomático.