DEV Community

Cover image for Go 1.28: container/set, ordered.Map y heap/v2 llegan a la stdlib
lu1tr0n
lu1tr0n

Posted on • Originally published at elsolitario.org

Go 1.28: container/set, ordered.Map y heap/v2 llegan a la stdlib

Go lleva 17 años sin un tipo set nativo en su librería estándar: los desarrolladores todavía escriben map[T]bool o map[T]struct{} cada vez que necesitan uno. El 28 de julio de 2026 el Go Collections working group publicó la propuesta #80590, un issue paraguas que agrupa siete paquetes nuevos de colecciones genéricas candidateando para Go 1.28: sets, mapas ordenados y un heap rediseñado.

TL;DR

  • El Go Collections working group publicó la propuesta #80590 el 28 de julio de 2026 para Go 1.28.- El grupo lo integran Jonathan Amsterdam, Alan Donovan, Robert Griesemer, Daniel Martí, Roger Peppe, Keith Randall e Ian Lance Taylor.- hash/maphash.Hasher (issue #70471) ya se liberó en Go 1.27 y define hash y equivalencia para tipos no comparables.- container/set.SetT se representa como map[T]struct{} y suma Union, Intersection y más operaciones de set.- container/ordered.MapK,V usa un árbol balanceado para permitir range queries ordenadas.- container/heap/v2.Heap (issue #77397) reemplaza la API actual de container/heap, que el equipo describe como difícil de usar.- La propuesta también evalúa mapas hash con orden de inserción (issue #80194) y stacks para una futura ronda.- Los nuevos paquetes viven dentro del árbol container ya existente para no chocar con el concepto de contenedores de Linux.

Introducción

El lenguaje sumó generics en Go 1.18 (2022) e iteradores nativos en Go 1.23 (2024). Esas dos piezas dejaron la puerta abierta para que tipos definidos en paquetes de librería alcancen una ergonomía comparable a la de slice y map, los únicos tipos de colección que Go trae de fábrica. La propuesta #80590 es el resultado de ese trabajo: un conjunto de colecciones genéricas pensadas para cubrir los huecos más citados por la comunidad Go en los últimos años, sin comprometer la simplicidad que caracteriza al lenguaje.

Qué pasó

El working group lo integran Jonathan Amsterdam, Alan Donovan, Robert Griesemer, Daniel Martí, Roger Peppe, Keith Randall e Ian Lance Taylor, todos con historial en el equipo central de Go. Se formó a fines de 2025 con un objetivo puntual: llevar estructuras de datos comunes a la librería estándar siguiendo los mismos principios de pragmatismo y simplicidad que rigen el resto del lenguaje.

La propuesta no es un solo paquete sino una sombrilla que enlaza siete piezas, cada una con su propio issue y su propio CL (change list, el equivalente en Gerrit a un pull request) en revisión activa. Tres ya tienen implementación publicada, dos están en discusión de diseño y dos quedaron marcadas para una futura ronda, entre ellas mapas hash con orden de inserción (issue #80194) y stacks genéricos.
Siete paquetes nuevos agrupados bajo un mismo issue paraguas.

Contexto e historia

Go nunca ocultó su apuesta por la simplicidad de slice y map como tipos incorporados, pero esa misma apuesta dejó afuera estructuras que otros lenguajes dan por sentadas. No hay sets nativos: la convención histórica es map[T]bool o map[T]struct{}, con la ambigüedad de que un valor false en un map[T]bool puede confundirse con la ausencia de la clave. Tampoco hay mapas ni sets ordenados basados en árboles: quedaban completamente afuera de la librería estándar.

El patrón habitual en Go para ordenar datos, construir un map[K]V y después ordenar sus claves con sort.Slice, funciona bien en la mayoría de los casos. Pero falla cuando el programa necesita una range query, por ejemplo todos los usuarios con ID entre 1000 y 2000, sin recorrer el mapa entero. Ahí es donde container/ordered.Map, respaldado por un árbol balanceado, cambia el enfoque: una consulta por rango deja de requerir un recorrido completo de la estructura.

📌 Nota: los métodos de set como Union(S) S no forman una interfaz común entre distintos tipos concretos de set: es el clásico problema del método binario. El working group lo resuelve con interfaces de restricción recursivas (F-bounded polymorphism) que permiten escribir funciones genéricas como Subset o ContainsAny sin fijar un tipo concreto de antemano.

Detalles técnicos y rendimiento de las colecciones genéricas

Cada paquete de la propuesta ataca un caso de uso puntual, y juntos empiezan a delinear una convención para las colecciones genéricas dentro del árbol container de la librería estándar. El equipo aclaró que prefiere el término collection en vez de container para no confundirlo con los contenedores al estilo Linux, aunque el código siga viviendo en ese árbol por compatibilidad histórica.
PaqueteQué resuelveEstado (julio 2026)Referenciahash/maphash.HasherHash y equivalencia personalizados para claves no comparablesLiberado en Go 1.27issue #70471container/hash.Map[K,V]Mapa hash que acepta el Hasher personalizadoEn CL, propuesto para 1.28issue #69559container/hash.Set[T]Set basado en un hash personalizadoEn CL, propuesto para 1.28issue #80584container/set.Set[T]Set canónico para tipos comparables, con Union e IntersectionEn CL, propuesto para 1.28issue #69230container/mapsetFunciones helper para tratar map[T]bool como set sin cambiar su tipoEn CL, propuesto para 1.28issue #77052container/ordered.Map[K,V]Mapa ordenado con árbol balanceado, útil para range queriesPropuesto para 1.28issue #60630container/heap/v2.HeapHeap genérico que reemplaza la API actual, considerada difícil de usarPropuesto para 1.28issue #77397
hash/maphash.Hasher, la pieza que ya llegó a Go 1.27, es la base de container/hash.Map y container/hash.Set: define una interfaz estándar de hash y equivalencia para cuando el tipo de clave no es comparable, como un slice o un map, o cuando la comparación por defecto del compilador da un resultado incorrecto, como pasa con los valores types.Type del paquete go/types, que necesitan comparación profunda (types.Identical) en vez de comparación de puntero. La documentación del paquete incluye un ejemplo de uso en un filtro de Bloom.
Union e Intersection llegan como métodos nativos de set.Set.

package main

import (
    "fmt"
    "container/set"
)

func main() {
    frameworks := set.Of("gin", "echo", "fiber")
    frameworks.Add("chi")
    fmt.Println(frameworks.Contains("echo")) // true
    fmt.Println(frameworks.Len())            // 4
}
Enter fullscreen mode Exit fullscreen mode

Este primer ejemplo crea un set de nombres de frameworks y agrega un elemento con Add. A diferencia de map[T]bool, no hay forma de confundir un valor false con una clave ausente: Contains devuelve directamente un booleano de pertenencia.

package main

import (
    "fmt"
    "container/set"
)

func main() {
    backendDevs := set.Of("ana", "bruno", "carla", "diego")
    frontendDevs := set.Of("carla", "diego", "elena", "fabio")

    fullstack := backendDevs.Intersection(frontendDevs)
    equipoCompleto := backendDevs.Union(frontendDevs)

    fmt.Println("Fullstack:", fullstack.Values())
    fmt.Println("Equipo completo:", equipoCompleto.Len()) // 6
}
Enter fullscreen mode Exit fullscreen mode

Este segundo ejemplo es más cercano a un caso real: cruzar dos equipos con Intersection para encontrar a los desarrolladores fullstack, y con Union para armar la nómina completa sin duplicados. Son las mismas operaciones que hoy cualquier equipo Go reimplementa a mano sobre un map[T]struct{}.

flowchart TD
    A["Propuesta en GitHub Issue"] --> B["CL en Gerrit (Code Review)"]
    B --> C["Revision del proposal committee"]
    C --> D{"Aceptada?"}
    D -->|"Si"| E["Merge en golang/go"]
    D -->|"No"| F["Cerrada o iterada"]
    E --> G[("go1.28 stdlib")]
Enter fullscreen mode Exit fullscreen mode

⚠️ Ojo: ninguno de estos paquetes, salvo hash/maphash.Hasher, forma parte todavía de un release estable de Go. Las firmas de método y los nombres de paquete pueden cambiar durante la revisión de la propuesta antes de llegar a Go 1.28.

Cómo empezar / probarlo

hash/maphash.Hasher ya se puede usar hoy porque viajó en Go 1.27: alcanza con import "hash/maphash" en cualquier proyecto con go.mod apuntando a esa versión o superior. El resto de los paquetes todavía vive en CLs individuales dentro del sistema Gerrit de revisión de Go, así que para probarlos antes del release hay que compilar el toolchain desde la rama de desarrollo (gotip) y aplicar el CL correspondiente, el mismo flujo que usa cualquier contribuidor del proyecto.

# Los mismos comandos funcionan igual en Linux, macOS y Windows (PowerShell o cmd)
go install golang.org/dl/gotip@latest
gotip download
gotip version
Enter fullscreen mode Exit fullscreen mode

Con gotip instalado y el CL de container/set.Set aplicado sobre el checkout local, se puede confirmar que la API está disponible inspeccionando la documentación generada directamente desde el código fuente:

gotip doc container/set.Set
Enter fullscreen mode Exit fullscreen mode

Ese comando lista los métodos exportados del tipo en ese punto del CL (Add, Contains, Union, Intersection y demás), la forma más directa de verificar qué firma quedó vigente en cada revisión sin depender de capturas de pantalla desactualizadas.

Impacto y análisis

Para el desarrollador de a pie, el cambio más inmediato no es una API nueva sino una convención: hoy, dos proyectos Go que necesitan un set eligen entre map[T]bool, map[T]struct{} o una librería de terceros, cada una con su propia superficie de API. Con container/set.Set como set canónico en la librería estándar, ese fragmento repetido en cada repositorio deja de tener sentido, y las firmas de funciones públicas de otras librerías pueden empezar a aceptar set.Set[T] como tipo de parámetro sin forzar una dependencia externa.

El caso de container/mapset apunta al lado opuesto del problema: código existente que ya usa map[T]bool o map[T]struct{} como set y no puede cambiar su tipo público sin romper compatibilidad. container/mapset ofrece funciones sueltas (Union, Intersection y otras) que operan sobre esos mapas legacy con exactamente la misma semántica que los métodos de set.Set, sin migrar el tipo subyacente.

El working group fue explícito sobre el alcance inicial: las primeras implementaciones buscan cumplir la API y el comportamiento asintótico esperado de la forma más simple posible. La optimización de constantes, reducir allocations o mejorar el uso de caché de CPU, queda fuera del proceso de propuesta y llegará, si llega, en iteraciones posteriores una vez que el diseño esté fijado.

Qué sigue

La propuesta está abierta a discusión pública en el issue #80590, con siete sub-propuestas enlazadas que se revisan y aceptan, o rechazan, de forma independiente dentro del proceso estándar de Go. El working group ya adelantó que evalúa una octava pieza, mapas hash con orden de inserción (issue #80194), y un tipo stack genérico para una ronda posterior, una vez resueltas las siete piezas actuales.

El milestone asignado es Go1.28, lo que en el calendario habitual de releases semestrales de Go ubicaría el lanzamiento estable hacia comienzos de 2027, aunque el proceso de propuesta puede extender o recortar ese calendario según el resultado de la revisión pública.

📖 Resumen en Telegram: Ver resumen

Probalo vos: corré go install golang.org/dl/gotip@latest && gotip download hoy mismo y aplicá el CL de container/set.Set del issue #69230 para ver el set canónico de Go antes de que llegue a un release estable.

Preguntas frecuentes

¿Qué es exactamente la propuesta #80590?

Es un issue paraguas del Go Collections working group que agrupa siete propuestas de paquetes de colecciones genéricas (sets, mapas hash, mapas ordenados y un heap rediseñado) candidateando para la librería estándar de Go 1.28.

¿Cuándo va a estar disponible en una versión estable de Go?

El milestone asignado es Go1.28. Solo hash/maphash.Hasher ya se liberó, en Go 1.27; el resto sigue en revisión de CL y puede cambiar antes del release final.

¿Por qué Go no tuvo sets nativos hasta ahora?

El lenguaje priorizó desde su diseño original la flexibilidad de slice y map como tipos incorporados. Recién con generics (Go 1.18) e iteradores (Go 1.23) se volvió práctico dar a tipos definidos en paquetes de librería una ergonomía comparable a la de los tipos nativos.

¿Qué diferencia hay entre container/set.Set y container/mapset?

container/set.Set[T] es un tipo nuevo, representado internamente como map[T]struct{}, con métodos como Union e Intersection. container/mapset ofrece las mismas operaciones como funciones sueltas para código legacy que ya usa map[T]bool o map[T]struct{} y no puede cambiar de tipo público.

¿Puedo usar alguno de estos paquetes en producción hoy?

Solo hash/maphash.Hasher, que viajó estable en Go 1.27. El resto vive en CLs individuales sobre gotip y todavía puede cambiar de nombre o de firma antes de llegar a un release estable.

¿container/heap/v2 reemplaza al container/heap actual?

Sí, es una API genérica pensada para reemplazar la interfaz heap.Interface actual, que el propio equipo de Go describe como difícil de usar correctamente.

Referencias

  • golang/go issue #80590: la propuesta paraguas del Go Collections working group, fuente primaria de este artículo.- pkg.go.dev/hash/maphash: documentación oficial del paquete ya liberado en Go 1.27, incluye Hasher y el ejemplo de filtro de Bloom.- go.dev/doc: documentación oficial del lenguaje y guía de contribución para compilar gotip y aplicar CLs.- github.com/golang/go: repositorio principal del proyecto, donde se discuten y revisan todos los CLs mencionados.

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.

Top comments (0)