Go 1.28 Generic Collection Types Proposal
Go is introducing a comprehensive set of generic collection types in Go 1.28 to provide standard, ergonomic data structures that were previously missing or implemented via workarounds. This move leverages the addition of generics in Go 1.18 and iterators in Go 1.23 to bring common data structures into the standard library while maintaining Go's core principles of pragmatism and simplicity.
New Standard Collection Types
The Go Collections working group proposes several new packages and types to standardize how developers handle sets, maps, and heaps.
Hash-Based Collections
container/hash.Map[K, V]: A hash-based map that supports custom hash functions and equivalence relations via thehash/maphash.Hasherinterface. This is particularly useful for key types that are not comparable (e.g., slices or maps) or require deep comparison.container/hash.Set[T]: A hash-based set implementation following the same custom hashing principles ascontainer/hash.Map.container/set.Set[T]: A canonical set for comparable elements, transparently represented asmap[T]struct{}. It provides standard set operations like Union and Intersection and is intended to replace the legacymap[T]boolormap[T]struct{}patterns.
Ordered and Specialized Collections
container/ordered.Map[K, V]: An ordered mapping implementation (currently using a balanced binary tree) designed for use cases where range queries are required, surpassing the performance of the common pattern of sorting map keys manually.container/heap/v2.Heap: A generic binary heap API designed to replace the existingcontainer/heapimplementation, which is widely considered difficult to use.
Helper Packages
container/mapset: A package of helper functions (Union, Intersection, etc.) designed to manipulate "legacy" sets (existingmap[T]struct{}code) without requiring API changes to existing code.
Abstract Collection Constraints
To ensure consistency across different collection implementations, the Go team has introduced unexported abstract constraint interfaces. These interfaces use F-bounded polymorphism (recursive constraint interfaces) to solve the "binary method problem," where methods like Union(S) S must ensure that the same concrete set type is used for both the operand and the result.
The internal hierarchy includes:
_AbstractCollection[E, C]: Defines basic operations likeClear(),Clone(),Contains(E), andLen()._AbstractMap[K, V, M]: Extends the collection interface with map-specific operations such asGet(K),Set(K, V), andKeys()._AbstractSet[E, S]: Extends the collection interface with set-specific operations includingUnion(S),Intersection(S), andSymmetricDifference(S).
While these interfaces are currently unexported to allow the Go team to learn from practice before committing to a public API, they serve as a blueprint for consistency across the standard library.
Design Rationales and API Conventions
The new collections API follows several specific design choices to optimize performance and ergonomics:
- Information-Rich Returns: Mutation methods report whether they changed the collection size.
Map.SetandMap.Deletereturn the previous value and a boolean to distinguish existing keys from zero values. - -With Variants: Set algebra operations come in two forms: a purely functional version (e.g.,
Union) that returns a new set, and a mutating version (e.g.,UnionWith) that modifies the left operand to avoid unnecessary allocations. - Asymptotic Performance: Certain operations like
DeleteFuncare kept in the interfaces because their specialized implementations (e.g., in tree-based maps) are asymptotically more efficient (O(n) vs O(n log n)) than generic loop-based implementations.
Community Perspectives
Community reaction to the proposal has been mixed, reflecting a long-standing debate over Go's evolution.
Some developers view the additions as a long-overdue modernization:
"Stuff like sets or a typed heap is long overdue."
Others argue that the language's slow adoption of these features mirrors a pattern of late arrival to industry standards:
"Step by step, Go is now learning the hard lessons every other language has learned over the last 20 years."
There is also a subset of the community that expresses concern that the addition of generics and complex collection types moves Go away from its original identity of simplicity for "poor programmers," with some suggesting that these changes make the language more complex for the average developer while benefiting library authors.