golang-data-structures by samber/cc-skills-golang
npx skills add https://github.com/samber/cc-skills-golang --skill golang-data-structures角色: 你是一位理解数据结构内部原理的 Go 工程师。你会根据内存布局、分配成本和访问模式来推理,为工作选择正确的结构,而不是最熟悉的那一个。
内置和标准库数据结构:内部原理、正确用法和选择指南。关于安全陷阱(nil 映射、append 别名、防御性拷贝),请参见 samber/cc-skills-golang@golang-safety 技能。关于通道和同步原语,请参见 samber/cc-skills-golang@golang-concurrency 技能。关于 string/byte/rune 的选择,请参见 samber/cc-skills-golang@golang-design-patterns 技能。
make(T, 0, n) / make(map[K]V, n) —— 避免重复的增长拷贝和重新哈希container/heap 处理优先队列, 仅当需要频繁中间插入时使用, 用于固定大小的环形缓冲区广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
container/listcontainer/ringstrings.Builder 必须优先用于构建字符串;bytes.Buffer 必须优先用于双向 I/O(同时实现 io.Reader 和 io.Writer)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)
// 确切大小已知
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 与 cap、头部拷贝、后备数组别名。
映射是具有 8 条目桶和溢出链的哈希表。它们是引用类型 —— 赋值一个映射会复制指针,而不是数据。
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 映射如何存储和哈希数据、桶溢出链、为什么映射从不收缩(以及如何处理)、比较映射性能与替代方案。
固定大小,值类型。赋值时完全复制。用于编译时已知大小的情况:
type Digest [32]byte // 固定大小,值类型
var grid [3][3]int // 多维
cache := map[[2]int]Result{} // 数组是可比较的 —— 可用作映射键
其他所有情况优先使用切片 —— 数组无法增长且按值传递(对于大尺寸开销昂贵)。
| 包 | 数据结构 | 最适合 |
|---|---|---|
container/list | 双向链表 | LRU 缓存,频繁的中间插入/删除 |
container/heap | 最小堆(优先队列) | Top-K,调度,Dijkstra |
container/ring | 环形缓冲区 | 滚动窗口,轮询 |
bufio | 缓冲读取器/写入器/扫描器 | 高效的小型读写 I/O |
容器类型使用 any(无类型安全) —— 考虑使用泛型包装器。容器模式、bufio 和示例 —— 何时使用每种容器类型、添加类型安全的泛型包装器,以及用于高效 I/O 的 bufio 模式。
纯字符串拼接使用 strings.Builder(避免 String() 时的拷贝),需要 io.Reader 或字节操作时使用 bytes.Buffer。两者都支持 Grow(n)。详细信息和比较
使用尽可能最严格的约束。映射键使用 comparable,排序使用 cmp.Ordered,领域特定排序使用自定义接口。
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 技能slices.Clone/Equal,请参见 samber/cc-skills-golang@golang-safety 技能sync.Map、sync.Pool 和所有同步原语,请参见 samber/cc-skills-golang@golang-concurrency 技能string 对比 []byte 对比 []rune、迭代器、流式处理,请参见 samber/cc-skills-golang@golang-design-patterns 技能any,请参见 samber/cc-skills-golang@golang-structs-interfaces 技能samber/cc-skills-golang@golang-code-style 技能| 错误 | 修复方法 |
|---|---|
| 在循环中增长切片而未预分配 | 每次增长都会复制整个后备数组 —— 每次增长 O(n)。使用 make([]T, 0, n) 或 slices.Grow |
在切片足以胜任时使用 container/list | 链表缓存局部性差(每个节点是单独的堆分配)。先进行基准测试 |
纯字符串构建使用 bytes.Buffer | Buffer 的 String() 会复制底层字节。strings.Builder 避免了这次拷贝 |
跨语句将 unsafe.Pointer 存储为 uintptr | GC 可能在语句间移动对象 —— uintptr 变成悬垂引用 |
| 映射中存储大型结构体值(拷贝开销) | 映射访问会复制整个值。对于大型值类型,使用 map[K]*V 以避免拷贝 |
每周安装量
97
代码库
GitHub 星标数
184
首次出现
3 天前
安全审计
安装于
opencode80
codex79
gemini-cli79
kimi-cli78
github-copilot78
cursor78
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.
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.
make(T, 0, n) / make(map[K]V, n) when size is known or estimable — avoids repeated growth copies and rehashingcontainer/heap for priority queues, container/list only when frequent middle insertions are needed, container/ring for fixed-size circular buffersstrings.Builder MUST be preferred for building strings; bytes.Buffer MUST be preferred for bidirectional I/O (implements both io.Reader and io.Writer)comparable for keys, custom interfaces for orderingunsafe.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 entriesA 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).
< 256 elements: capacity doubles
= 256 elements: grows by ~25% (
newcap += (newcap + 3*256) / 4)
Each growth copies the entire backing array — O(n)
// Exact size known
users := make([]User, 0, len(ids))
// Approximate size known
results := make([]Result, 0, estimatedCount)
// Pre-grow before bulk append (Go 1.21+)
s = slices.Grow(s, additionalNeeded)
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.
Maps are hash tables with 8-entry buckets and overflow chains. They are reference types — assigning a map copies the pointer, not the data.
m := make(map[string]*User, len(users)) // avoids rehashing during population
maps Package Quick Reference (Go 1.21+)| Function | Purpose |
|---|---|
Collect (1.23+) | Build map from iterator |
Insert (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.
Fixed-size, value types. Copied entirely on assignment. Use for compile-time-known sizes:
type Digest [32]byte // fixed-size, value type
var grid [3][3]int // multi-dimensional
cache := map[[2]int]Result{} // arrays are comparable — usable as map keys
Prefer slices for everything else — arrays cannot grow and pass by value (expensive for large sizes).
| Package | Data Structure | Best For |
|---|---|---|
container/list | Doubly-linked list | LRU caches, frequent middle insertion/removal |
container/heap | 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.
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
Use the tightest constraint possible. comparable for map keys, cmp.Ordered for sorting, custom interfaces for domain-specific ordering.
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 }
Writing Generic Data Structures — Using Go 1.18+ generics for type-safe containers, understanding constraint satisfaction, and building domain-specific generic types.
| Type | Use Case | Zero Value |
|---|---|---|
*T | Normal indirection, mutation, optional values | nil |
unsafe.Pointer | 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.
| Type | Copy Behavior | Independence |
|---|---|---|
int, float, bool, string | Value (deep copy) | Fully independent |
array, struct | Value (deep copy) | Fully independent |
slice | Header copied, backing array shared | Use |
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 queueWhen using third-party libraries, refer to their official documentation and code examples for current API signatures. Context7 can help as a discoverability platform.
samber/cc-skills-golang@golang-performance skill for struct field alignment, memory layout optimization, and cache localitysamber/cc-skills-golang@golang-safety skill for nil map/slice pitfalls, append aliasing, defensive copying, slices.Clone/Equalsamber/cc-skills-golang@golang-concurrency skill for channels, sync.Map, sync.Pool, and all sync primitivessamber/cc-skills-golang@golang-design-patterns skill for string vs []byte vs , iterators, streaming| 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 slices.Grow |
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 across statements |
Weekly Installs
97
Repository
GitHub Stars
184
First Seen
3 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode80
codex79
gemini-cli79
kimi-cli78
github-copilot78
cursor78
ESLint迁移到Oxlint完整指南:JavaScript/TypeScript项目性能优化工具
1,700 周安装
slices.Clonemap | 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 |
[]runesamber/cc-skills-golang@golang-structs-interfaces skill for struct composition, embedding, and generics vs anysamber/cc-skills-golang@golang-code-style skill for slice/map initialization styleuintptrGC 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 |