Persona: You are a Go engineer who understands data structure internals. You choose the right structure for the job — not the most familiar one — by reasoning about memory layout, allocation cost, and access patterns.
Go Data Structures
Built-in and standard library data structures: internals, correct usage, and selection guidance. For safety pitfalls (nil maps, append aliasing, defensive copies) see samber/cc-skills-golang@golang-safety skill. For channels and sync primitives see samber/cc-skills-golang@golang-concurrency skill. For string/byte/rune choice see samber/cc-skills-golang@golang-design-patterns skill.
Best Practices Summary
- 1. Preallocate slices and maps with
make(T, 0, n) / make(map[K]V, n) when size is known or estimable — avoids repeated growth copies and rehashing - Arrays SHOULD be preferred over slices only for fixed, compile-time-known sizes (hash digests, IPv4 addresses, matrix dimensions)
- NEVER rely on slice capacity growth timing — the growth algorithm changed between Go versions and may change again; your code should not depend on when a new backing array is allocated
- Use
container/heap for priority queues, container/list only when frequent middle insertions are needed, container/ring for fixed-size circular buffers strings.Builder MUST be preferred for building strings; bytes.Buffer MUST be preferred for bidirectional I/O (implements both io.Reader and io.Writer)- Generic data structures SHOULD use the tightest constraint possible —
comparable for keys, custom interfaces for ordering unsafe.Pointer MUST only follow the 6 valid conversion patterns from the Go spec — NEVER store in a uintptr variable across statementsweak.Pointer[T] (Go 1.24+) SHOULD be used for caches and canonicalization maps to allow GC to reclaim entries
Slice Internals
A slice is a 3-word header: pointer, length, capacity. Multiple slices can share a backing array (→ see samber/cc-skills-golang@golang-safety for aliasing traps and the header diagram).
Capacity Growth
- - < 256 elements: capacity doubles
- > = 256 elements: grows by ~25% (
newcap += (newcap + 3*256) / 4) - Each growth copies the entire backing array — O(n)
Preallocation
CODEBLOCK0
slices Package (Go 1.21+)
Key functions: Sort/SortFunc, BinarySearch, Contains, Compact, Grow. For Clone, Equal, DeleteFunc → see samber/cc-skills-golang@golang-safety skill.
Slice Internals Deep Dive — Full slices package reference, growth mechanics, len vs cap, header copying, backing array aliasing.
Map Internals
Maps are hash tables with 8-entry buckets and overflow chains. They are reference types — assigning a map copies the pointer, not the data.
Preallocation
CODEBLOCK1
maps Package Quick Reference (Go 1.21+)
| Function | Purpose |
|---|
| INLINECODE33 (1.23+) | Build map from iterator |
| INLINECODE34 (1.23+) |
Insert entries from iterator |
|
All (1.23+) | Iterator over all entries |
|
Keys,
Values | Iterators over keys/values |
For Clone, Equal, sorted iteration → see samber/cc-skills-golang@golang-safety skill.
Map Internals Deep Dive — How Go maps store and hash data, bucket overflow chains, why maps never shrink (and what to do about it), comparing map performance to alternatives.
Arrays
Fixed-size, value types. Copied entirely on assignment. Use for compile-time-known sizes:
CODEBLOCK2
Prefer slices for everything else — arrays cannot grow and pass by value (expensive for large sizes).
container/ Standard Library
| Package | Data Structure | Best For |
|---|
| INLINECODE41 | Doubly-linked list | LRU caches, frequent middle insertion/removal |
| INLINECODE42 |
Min-heap (priority queue) | Top-K, scheduling, Dijkstra |
|
container/ring | Circular buffer | Rolling windows, round-robin |
|
bufio | Buffered reader/writer/scanner | Efficient I/O with small reads/writes |
Container types use any (no type safety) — consider generic wrappers. Container Patterns, bufio, and Examples — When to use each container type, generic wrappers to add type safety, and bufio patterns for efficient I/O.
strings.Builder vs bytes.Buffer
Use strings.Builder for pure string concatenation (avoids copy on String()), bytes.Buffer when you need io.Reader or byte manipulation. Both support Grow(n). Details and comparison
Generic Collections (Go 1.18+)
Use the tightest constraint possible. comparable for map keys, cmp.Ordered for sorting, custom interfaces for domain-specific ordering.
CODEBLOCK3
Writing Generic Data Structures — Using Go 1.18+ generics for type-safe containers, understanding constraint satisfaction, and building domain-specific generic types.
Pointer Types
| Type | Use Case | Zero Value |
|---|
| INLINECODE54 | Normal indirection, mutation, optional values | INLINECODE55 |
| INLINECODE56 |
FFI, low-level memory layout (6 spec patterns only) |
nil |
|
weak.Pointer[T] (1.24+) | Caches, canonicalization, weak references | N/A |
Pointer Types Deep Dive — Normal pointers, unsafe.Pointer (the 6 valid spec patterns), and weak.Pointer[T] for GC-safe caches that don't prevent cleanup.
Copy Semantics Quick Reference
| Type | Copy Behavior | Independence |
|---|
INLINECODE61 , float, bool, INLINECODE64 | Value (deep copy) | Fully independent |
| INLINECODE65 , INLINECODE66 |
Value (deep copy) | Fully independent |
|
slice | Header copied, backing array shared | Use
slices.Clone |
|
map | Reference copied | Use
maps.Clone |
|
channel | Reference copied | Same channel |
|
*T (pointer) | Address copied | Same underlying value |
|
interface | Value copied (type + value pair) | Depends on held type |
Third-Party Libraries
For advanced data structures (trees, sets, queues, stacks) beyond the standard library:
- -
emirpasic/gods — comprehensive collection library (trees, sets, lists, stacks, maps, queues) deckarep/golang-set — thread-safe and non-thread-safe set implementationsgammazero/deque — fast double-ended queue
When using third-party libraries, refer to their official documentation and code examples for current API signatures. Context7 can help as a discoverability platform.
Cross-References
- - → See
samber/cc-skills-golang@golang-performance skill for struct field alignment, memory layout optimization, and cache locality - → See
samber/cc-skills-golang@golang-safety skill for nil map/slice pitfalls, append aliasing, defensive copying, slices.Clone/ INLINECODE80 - → See
samber/cc-skills-golang@golang-concurrency skill for channels, sync.Map, sync.Pool, and all sync primitives - → See
samber/cc-skills-golang@golang-design-patterns skill for string vs []byte vs []rune, iterators, streaming - → See
samber/cc-skills-golang@golang-structs-interfaces skill for struct composition, embedding, and generics vs INLINECODE89 - → See
samber/cc-skills-golang@golang-code-style skill for slice/map initialization style
Common Mistakes
| Mistake | Fix |
|---|
| Growing a slice in a loop without preallocation | Each growth copies the entire backing array — O(n) per growth. Use make([]T, 0, n) or INLINECODE92 |
Using container/list when a slice would suffice |
Linked lists have poor cache locality (each node is a separate heap allocation). Benchmark first |
|
bytes.Buffer for pure string building | Buffer's
String() copies the underlying bytes.
strings.Builder avoids this copy |
|
unsafe.Pointer stored as
uintptr across statements | GC can move the object between statements — the
uintptr becomes a dangling reference |
| Large struct values in maps (copying overhead) | Map access copies the entire value. Use
map[K]*V for large value types to avoid the copy |
References
角色定位: 你是一位理解数据结构内部原理的 Go 工程师。你会通过推理内存布局、分配成本和访问模式,为任务选择正确的数据结构——而不是最熟悉的那一个。
Go 数据结构
内置和标准库数据结构:内部原理、正确用法和选择指南。关于安全陷阱(nil 映射、追加别名、防御性拷贝),请参阅 samber/cc-skills-golang@golang-safety 技能。关于通道和同步原语,请参阅 samber/cc-skills-golang@golang-concurrency 技能。关于字符串/字节/符文的选择,请参阅 samber/cc-skills-golang@golang-design-patterns 技能。
最佳实践总结
- 1. 预分配切片和映射,当大小已知或可估算时,使用 make(T, 0, n) / make(map[K]V, n)——避免重复的增长拷贝和重新哈希
- 数组 仅应在固定、编译时已知大小(哈希摘要、IPv4 地址、矩阵维度)时优先于切片使用
- 永远不要依赖切片容量增长时机——增长算法在 Go 版本之间已发生变化,并且可能再次改变;你的代码不应依赖于何时分配新的后备数组
- 对于优先级队列使用 container/heap,仅当需要频繁的中间插入时使用 container/list,对于固定大小的循环缓冲区使用 container/ring
- 构建字符串时 必须 优先使用 strings.Builder;对于双向 I/O(同时实现 io.Reader 和 io.Writer)必须 优先使用 bytes.Buffer
- 泛型数据结构应使用 最严格的约束——键使用 comparable,排序使用自定义接口
- unsafe.Pointer 必须仅遵循 Go 规范中的 6 种有效转换模式——永远不要跨语句存储在 uintptr 变量中
- 对于缓存和规范化映射,应使用 weak.Pointer[T](Go 1.24+)以允许 GC 回收条目
切片内部原理
切片是一个 3 字头:指针、长度、容量。多个切片可以共享一个后备数组(→ 关于别名陷阱和头部图,请参阅 samber/cc-skills-golang@golang-safety)。
容量增长
- - < 256 个元素:容量翻倍
- >= 256 个元素:增长约 25%(newcap += (newcap + 3*256) / 4)
- 每次增长都会拷贝整个后备数组——O(n)
预分配
go
// 确切大小已知
users := make([]User, 0, len(ids))
// 近似大小已知
results := make([]Result, 0, estimatedCount)
// 批量追加前预增长 (Go 1.21+)
s = slices.Grow(s, additionalNeeded)
slices 包 (Go 1.21+)
关键函数:Sort/SortFunc、BinarySearch、Contains、Compact、Grow。关于 Clone、Equal、DeleteFunc → 请参阅 samber/cc-skills-golang@golang-safety 技能。
切片内部原理深入探讨 — 完整的 slices 包参考、增长机制、len vs cap、头部拷贝、后备数组别名。
映射内部原理
映射是带有 8 条目桶和溢出链的哈希表。它们是引用类型——赋值映射会拷贝指针,而不是数据。
预分配
go
m := make(map[string]*User, len(users)) // 避免在填充期间重新哈希
maps 包快速参考 (Go 1.21+)
| 函数 | 用途 |
|---|
| Collect (1.23+) | 从迭代器构建映射 |
| Insert (1.23+) |
从迭代器插入条目 |
| All (1.23+) | 所有条目的迭代器 |
| Keys, Values | 键/值的迭代器 |
关于 Clone、Equal、排序迭代 → 请参阅 samber/cc-skills-golang@golang-safety 技能。
映射内部原理深入探讨 — Go 映射如何存储和哈希数据、桶溢出链、映射为何从不收缩(以及如何处理)、将映射性能与替代方案进行比较。
数组
固定大小,值类型。赋值时完全拷贝。用于编译时已知大小:
go
type Digest [32]byte // 固定大小,值类型
var grid [3][3]int // 多维
cache := map[[2]int]Result{} // 数组是可比较的——可用作映射键
其他所有情况优先使用切片——数组不能增长且按值传递(对于大尺寸来说代价高昂)。
container/ 标准库
| 包 | 数据结构 | 最适合用于 |
|---|
| container/list | 双向链表 | LRU 缓存、频繁的中间插入/删除 |
| container/heap |
最小堆(优先队列) | Top-K、调度、Dijkstra |
| container/ring | 循环缓冲区 | 滚动窗口、轮询 |
| bufio | 带缓冲的读取器/写入器/扫描器 | 小规模读/写的高效 I/O |
容器类型使用 any(无类型安全)——考虑泛型包装器。容器模式、bufio 和示例 — 何时使用每种容器类型、添加类型安全的泛型包装器,以及用于高效 I/O 的 bufio 模式。
strings.Builder vs bytes.Buffer
对于纯字符串拼接使用 strings.Builder(避免 String() 上的拷贝),当需要 io.Reader 或字节操作时使用 bytes.Buffer。两者都支持 Grow(n)。详情和比较
泛型集合 (Go 1.18+)
使用尽可能最严格的约束。映射键使用 comparable,排序使用 cmp.Ordered,领域特定排序使用自定义接口。
go
type Set[T comparable] map[T]struct{}
func (s Set[T]) Add(v T) { s[v] = struct{}{} }
func (s Set[T]) Contains(v T) bool { _, ok := s[v]; return ok }
编写泛型数据结构 — 使用 Go 1.18+ 泛型实现类型安全的容器、理解约束满足,以及构建领域特定的泛型类型。
指针类型
| 类型 | 用例 | 零值 |
|---|
| *T | 普通间接引用、修改、可选值 | nil |
| unsafe.Pointer |
FFI、底层内存布局(仅 6 种规范模式) | nil |
| weak.Pointer[T] (1.24+) | 缓存、规范化、弱引用 | N/A |
指针类型深入探讨 — 普通指针、unsafe.Pointer(6 种有效规范模式),以及用于不阻止清理的 GC 安全缓存的 weak.Pointer[T]。
拷贝语义快速参考
| 类型 | 拷贝行为 | 独立性 |
|---|
| int, float, bool, string | 值拷贝(深拷贝) | 完全独立 |
| array, struct |
值拷贝(深拷贝) | 完全独立 |
| slice | 头部拷贝,后备数组共享 | 使用 slices.Clone |
| map | 引用拷贝 | 使用 maps.Clone |
| channel | 引用拷贝 | 同一通道 |
| *T (指针) | 地址拷贝 | 同一底层值 |
| interface | 值拷贝(类型 + 值对) | 取决于持有的类型 |
第三方库
对于超出标准库的高级数据结构(树、集合、队列、栈):
- - emirpasic/gods — 全面的集合库(树、集合、列表、栈、映射、队列)
- deckarep/golang-set — 线程安全和非线程安全的集合实现
- gammazero/deque — 快速双端队列
使用第三方库时,请参考其官方文档和代码示例以获取当前 API 签名。Context7 可以作为发现平台提供帮助。
交叉引用
- - → 关于结构体字段对齐、内存布局优化和缓存局部性,请参阅 samber/cc-skills-golang@golang-performance 技能
- → 关于 nil 映射/切片陷阱、追加别名、防御性拷贝、