Go 1.28 泛型集合类型提议

Go 正在 Go 1.28 中引入一套全面的泛型集合类型,以提供之前缺失或通过变通方法实现的标准、符合人体工程学的数据结构。此举利用了 Go 1.18 中泛型的引入和 Go 1.23 中的迭代器,旨在将常见的数据结构引入标准库,同时保持 Go 务实和简单的核心原则。

New Standard Collection Types

Go Collections 工作组提议了几个新包和类型,以标准化开发者处理集合(sets)、映射(maps)和堆(heaps)的方式。

Hash-Based Collections

  • container/hash.Map[K, V]: 一个基于哈希的映射,通过 hash/maphash.Hasher 接口支持自定义哈希函数和等价关系。这对于不可比较的键类型(例如切片或映射)或需要深度比较的类型特别有用。
  • container/hash.Set[T]: 一个基于哈希的集合实现,遵循与 container/hash.Map 相同的自定义哈希原则。
  • container/set.Set[T]: 用于可比较元素的规范集合,透明地表示为 map[T]struct{}。它提供标准的集合操作,如 Union 和 Intersection,旨在取代传统的 map[T]boolmap[T]struct{} 模式。

Ordered and Specialized Collections

  • container/ordered.Map[K, V]: 一个有序映射实现(目前使用平衡二叉树),专为需要范围查询的用例设计,其性能优于手动对 map 键进行排序的常见模式。
  • container/heap/v2.Heap: 一个泛型二叉堆 API,旨在取代现有的 container/heap 实现,后者被广泛认为难以使用。

Helper Packages

  • container/mapset: 一个包含辅助函数的包(Union, Intersection, 等),旨在操作“传统”集合(现有的 map[T]struct{} 代码)而无需对现有代码进行 API 更改。

Abstract Collection Constraints

为了确保不同集合实现之间的一致性,Go 团队引入了未导出的抽象约束接口。这些接口使用 F-bounded polymorphism(递归约束接口)来解决“二元方法问题”,即像 Union(S) S 这样的方法必须确保操作数和结果都使用相同的具体集合类型。

内部层级结构包括:

  • _AbstractCollection[E, C]: 定义了基本操作,如 Clear(), Clone(), Contains(E), 和 Len()
  • _AbstractMap[K, V, M]: 扩展了集合接口,增加了 map 特有的操作,如 Get(K), Set(K, V), 和 Keys()
  • _AbstractSet[E, S]: 扩展了集合接口,增加了 set 特有的操作,包括 Union(S), Intersection(S), 和 SymmetricDifference(S)

虽然这些接口目前是未导出的,以便让 Go 团队在投入使用公共 API 之前从实践中学习,但它们作为标准库中保持一致性的蓝图。

Design Rationales and API Conventions

新的集合 API 遵循了一些特定的设计选择,以优化性能和人体工程学:

  • Information-Rich Returns: 变动方法会报告它们是否改变了集合的大小。Map.SetMap.Delete 返回之前的值以及一个布尔值,以区分现有键与零值。
  • -With Variants: 集合代数操作有两种形式:一种是纯函数式版本(例如 Union)返回一个新集合,另一种是变动版本(例如 UnionWith)修改左操作数以避免不必要的分配。
  • Asymptotic Performance: 某些操作(如 DeleteFunc)保留在接口中,是因为它们的专门化实现(例如在基于树的映射中)在渐近性能上比通用的基于循环的实现更高效(O(n) vs O(n log n))。

Community Perspectives

社区对该提议的反应是复杂的,反映了关于 Go 语言演进的长期争论。

一些开发者认为这些新增内容是迟到已久的现代化改造:

"Stuff like sets or a typed heap is long overdue."

其他人则认为,语言对这些功能的缓慢采用反映了其在行业标准方面“姗姗来迟”的模式:

"Step by step, Go is now learning the hard lessons every other language has learned over the last 20 years."

也有部分社区成员表示担忧,认为泛型和复杂集合类型的引入会将 Go 从其最初为“弱程序员”设计的简单性身份中带离,一些人建议这些变化会使语言对普通开发者来说变得更复杂,而有利于库作者。

Sources