메뉴
HN
Hacker News • 56일 전

Go 언어 1.28 표준 라이브러리에 제네릭 컬렉션 타입 추가 제안

IMP
7/10
핵심 요약

Go 언어 개발팀이 제네릭을 활용한 다양한 컬렉션 데이터 구조(Set, Map, Heap 등)를 표준 라이브러리에 추가하는 제안을 발표했습니다. 그동안 부족했던 기본 자료구조와 불편했던 세트(Set) 구현 방식을 개선하여 개발자 편의성과 성능을 크게 높일 수 있는 중요한 업데이트입니다. 향후 Go 1.28 버전에서 정식으로 도입될 예정입니다.

번역된 본문

배경: Go 컬렉션 워킹 그룹은 Go의 익숙한 원칙인 실용주의와 단순성을 바탕으로, 일반적인 컬렉션 데이터 구조를 표준 라이브러리에 도입하기 위해 2025년 말에 결성되었습니다. 이 그룹은 Jonathan Amsterdam, Alan Donovan, Robert Griesemer, Daniel Martí, Roger Peppe, Keith Randall, 그리고 Ian Lance Taylor로 구성되어 있습니다. 이제 우리는 논의 결과를 커뮤니티와 공유할 준비가 되었습니다. 이 이슈는 Go 1.28을 위한 새로운 컬렉션 API에 대한 여러 관련 제안을 논의하기 위한 포괄적인 페이지입니다. 주요 테마에 대한 높은 수준의 개요를 제시하며, 구체적인 제안 및 관련 구현 코드(CL) 링크를 제공합니다.

Go는 현재 라이브러리에서 제공하는 컬렉션 타입이 거의 없으며, 처음부터 언어에 내장된 슬라이스(Slice)와 맵(Map) 타입의 유연성을 강조해 왔습니다. 제공되는 것 중 가장 중요한 것은 우선순위 큐에 사용되는 힙(Heap)입니다. 심지어 세트(Set)조차도 부재하여, 전통적으로 map[T]bool 또는 map[T]struct{}로 표현해 왔습니다. 이진 트리를 기반으로 하는 순서가 있는 맵과 세트는 전혀 존재하지 않았습니다.

하지만 Go 1.18에 제네릭(Generics)이 추가되고 Go 1.23에 이터레이터(Iterators)가 도입되면서, 라이브러리에서 정의한 타입이 내장 타입과 비슷한 수준의 인체공학적(사용하기 편리한) 설계를 갖출 수 있게 되었고, 슬라이스와 맵에 대한 많은 일반적인 작업들을 라이브러리 함수 호출로 표현할 수 있게 되었습니다. 이 작업은 몇 가지 중요한 데이터 타입을 표준 라이브러리에 추가하고, 향후 추가될 기능들을 위한 API 규칙을 확립하는 것을 목표로 합니다.

제안: 제안된 추가 사항은 다음과 같습니다:

#70471, CL 657296 (Go 1.27에 릴리스됨): hash/maphash.Hasher: 임의의 데이터 타입에 대해 사용자 정의 해시 함수와 동등성 비교 관계를 표현하기 위한 표준 인터페이스입니다. 이는 map[K]V에서 사용하는 컴파일러 정의 기본 방식과 다를 수 있으며, 키 타입이 비교 불가능할 때(예: 슬라이스나 맵) 또는 기본 비교가 잘못된 결과를 낼 때(예: 깊은 비교 연산이 필요한 types.Type 값) 유용합니다. 이 패키지 문서에는 이를 블룸 필터(Bloom filter)에 사용하는 예제가 포함되어 있습니다.

#69559, CL 612217: container/hash.Map[K,V]: 위에서 언급한 사용자 정의 해시 함수를 사용하는 해시 기반 맵입니다.

#80584, CL 741160: container/hash.Set[T]: 동일한 방식의 해시 기반 세트입니다.

#69230, CL 745441: container/set.Set[T]: 요소가 비교 가능한 세트를 위한 공식적인(canonical) 데이터 타입입니다. 이는 map[T]struct{}로 투명하게 표현되며 합집합(Union) 및 교집합(Intersection)과 같은 모든 일반적인 세트 연산을 지원합니다. map[T]bool 및 map[T]struct{}를 기반으로 한 "기존" 세트보다 사용하기 편리하며, map[T]bool에서 발생할 수 있는 false 값에 대한 모호성을 방지합니다. 향후 대부분의 새로운 Go API에서 표준 세트 역할을 할 것으로 기대됩니다.

#77052, CL 724420: container/mapset: API를 변경할 수 없는 기존 코드에서 기존 방식의 세트를 편리하게 다루기 위한 헬퍼 함수(합집합, 교집합 등) 패키지입니다. 이러한 함수들은 set.Set의 메서드와 완전히 동일하게 작동합니다.

#60630: container/ordered.Map[K,V]: 순서가 있는 맵입니다. 현재 구현은 균형 이진 트리를 사용하지만, 설계상 이에 국한되지는 않습니다. 일반적인 Go 패턴인 map[K]V를 만들고 키를 정렬하는 방식은 대부분의 경우 잘 작동하지만, 범위 쿼리(Range query)가 필요한 경우와 같이 때로는 다른 데이터 구조가 훨씬 더 나은 성능을 발휘합니다.

#77397: container/heap/v2.Heap: 표준 라이브러리의 기존 힙을 대체하기 위한 제네릭 이진 힙 API입니다.

원문 보기
원문 보기 (영어)
Uh oh! There was an error while loading. Please reload this page . golang / go Public Notifications You must be signed in to change notification settings Fork 19.2k Star 135k proposal: container/...: generic collection types #80590 New issue Copy link New issue Copy link Open Open proposal: container/...: generic collection types #80590 Copy link Labels Proposal Milestone Go1.28 Description adonovan opened on Jul 28, 2026 Issue body actions Background: The Go Collections working group was formed in late 2025 with the purpose of bringing common collection data structures to the standard library, guided by the familiar Go principles of pragmatism and simplicity. Alphabetically by last name, the group consists of Jonathan Amsterdam ( @jba ), Alan Donovan ( @adonovan ), Robert Griesemer ( @griesemer ), Daniel Martí ( @mvdan ), Roger Peppe ( @rogpeppe ), Keith Randall ( @khr ), and Ian Lance Taylor ( @ianlancetaylor ). We’ve now reached a point where we’re ready to share our results with the community. This issue is an umbrella for discussing several related proposals for new collections APIs for Go 1.28. It presents a high level overview of the themes, and links to the various concrete proposals and associated implementation CLs. Go currently provides few collection types in its library, and from the outset we have emphasized the flexibility of the language’s built-in slice and map types. Of those provided, the most important is the heap, used for priority queues. Even sets are absent; they are conventionally expressed in terms of map[T]bool or map[T]struct{}. Ordered maps and sets based on binary trees are entirely absent. Since the addition of generics in Go 1.18 and iterators in Go 1.23, it has become possible for library-defined types to achieve comparable ergonomics to built-in types, and for many common operations on slices and maps to be expressed as calls to library functions. This work seeks to add several of the more important data types to the standard library, and to establish conventions for their APIs and those of future additions. Proposal: The proposed additions include: #70471 , CL 657296 (released in go1.27): hash/maphash.Hasher : a standard interface for expressing custom hash functions and equivalence relations for arbitrary data types. These may differ from the compiler-defined ones used by map[K]V, and are useful when the key type is not comparable (such as a slice or map), or when the default comparison yields the wrong result (such as for types.Type values, which need the deep comparison operation types.Identical ). Its package docs include an example of its use in a Bloom filter . #69559 , CL 612217 : container/hash.Map[K,V] : a hash-based Map that uses the custom hash functions mentioned above. #80584 , CL 741160 : container/hash.Set[T] : a hash-based Set along the same lines. #69230 , CL 745441 : container/set.Set[T] : a canonical data type for sets whose elements are comparable. It is transparently represented as map[T]struct{} and supports all the usual set operations such as Union and Intersection. It is more convenient than “legacy” sets based on map[T]bool and map[T]struct{}, and avoids ambiguity about potential false values in a map[T]bool. We expect it to become the standard set in most new Go APIs. #77052 , CL 724420 : container/mapset : a package of helper functions (Union, Intersection, and so on) for conveniently manipulating legacy sets as sets in existing code whose API cannot be changed. These functions are exactly parallel to the methods of set.Set. #60630 : container/ordered.Map[K,V] : an ordered mapping. The current implementation uses a balanced binary tree, but nothing in the design requires that. The common Go pattern of building a map[K]V then sorting its keys performs well in most cases, but on occasion, such as when a range query is needed, other data structures perform much better. #77397 : container/heap/v2.Heap : a generic binary heap API to replace the standard library's existing heap, which can be difficult to use. We expect to consider additional proposals in due course, such as insertion-ordered hash maps ( #80194 ) and stacks . The initial implementations of all the proposed data structures aim to satisfy the API and asymptotic performance expectations as simply as possible. There are doubtless many opportunities for later optimizations to reduce constant factors, but they are out of scope of the proposal process. Though the new packages will live in the existing container tree, we prefer the term “collection” to avoid confusion with the container virtualization concept from Linux. Abstract collection constraint interfaces Most of the methods of the new Map and Set types are not particular to any concrete representation type, but are common across all Maps and Sets. However, they are not really implementions of a common interface type because of the “ binary method problem ”: if each set data type S has a Union method of the form func (S) Union(S) S , then the Union methods of different set types are incompatible, so they have no common ordinary interface. To express this abstract Set type, we must use F-bounded polymorphism , or recursive constraint interfaces. CL 761460 adds to the container package unexported abstract Collection, Set, and Map constraint interface types that permit package implementors to write abstract helper functions (such as ContainsAny, Subset, or Arbitrary) that work across a range of concrete collection, set or map types. We reproduce these interfaces below, with some brief commentary, to help give a high-level picture but they are not part of any proposal . They merely serve to guarantee conformance in tests. See the individual proposals for more detail. // _AbstractCollection models a collection C of elements E, // such as *hash.Map, *hash.Set, *ordered.Map, or set.Set. type _AbstractCollection [ E any , C _AbstractCollection [ E , C ]] interface { Clear () Clone () C Contains ( E ) bool ContainsAll (iter. Seq [ E ]) bool Len () int String () string } // _AbstractMap models a mapping M from keys K to values V, // such as *hash.Map or *ordered.Map. type _AbstractMap [ K , V any , M _AbstractMap [ K , V , M ]] interface { _AbstractCollection [ K , M ] All () iter. Seq2 [ K , V ] At ( K ) V Delete ( K ) ( V , bool ) DeleteAll (iter. Seq [ K ]) bool DeleteFunc ( func ( K , V ) bool ) bool Get ( K ) ( V , bool ) Keys () iter. Seq [ K ] Set ( K , V ) ( V , bool ) SetAll (iter. Seq2 [ K , V ]) bool Values () iter. Seq [ V ] } // _AbstractSet models a set S of elements E, // such as *hash.Set, or set.Set. type _AbstractSet [ E any , S _AbstractSet [ E , S ]] interface { _AbstractCollection [ E , S ] All () iter. Seq [ E ] Delete ( E ) bool DeleteAll (iter. Seq [ E ]) bool DeleteFunc ( func ( E ) bool ) bool Difference ( S ) S DifferenceWith ( S ) Equal ( S ) bool Insert ( E ) bool InsertAll (iter. Seq [ E ]) bool Intersection ( S ) S IntersectionWith ( S ) Intersects ( S ) bool SymmetricDifference ( S ) S SymmetricDifferenceWith ( S ) Union ( S ) S UnionWith ( S ) } For now these abstract types are non-exported and merely serve as documentation of Go’s conventions to help ensure consistency. We do not propose to publish them yet, but may do so a later release after gaining experience with the concrete collection types. In the meantime, users can define minimal constraint types as needed, as in this example (from CL 761460 ) of a generic Take function over abstract sets: // _TakeSet defines an abstraction of a set sufficient for the [Take] function. type _TakeSet [ E any , S _TakeSet [ E , S ]] interface { All () iter. Seq [ E ] Delete ( E ) bool } // Take removes and returns an arbitrary element from a set. // It returns zero if the set was empty. func Take [ S _TakeSet [ E , S ], E any ]( set S ) ( e E , found bool ) { for e = range set . All () { found = true set . Delete ( e ) break } return } There is a certain arbitrariness to the set of methods included in each interfac