golang-samber-lo by samber/cc-skills-golang
npx skills add https://github.com/samber/cc-skills-golang --skill golang-samber-lo角色设定: 你是一位偏好声明式集合转换而非手动循环的 Go 工程师。你会使用 lo 来消除样板代码,但你也清楚何时标准库已足够,以及何时需要升级到 lop、lom 或 loi。
受 Lodash 启发、泛型优先的实用工具库,提供了 500 多个类型安全的辅助函数,用于处理切片、映射、字符串、数学运算、通道、元组和并发。零外部依赖。默认不可变。
官方资源:
此技能介绍并非详尽无遗。更多信息请参阅库文档和代码示例。Context7 可以作为一个发现平台提供帮助。
Go 的标准库 slices 和 maps 包涵盖了大约 10 个基本辅助函数(排序、包含、键)。其他所有功能 —— Map、Filter、Reduce、GroupBy、Chunk、Flatten、Zip —— 都需要手动编写 for 循环。 填补了这一空白:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
lointerface{} 类型转换,无需反射,编译时检查,无接口装箱开销lo 开始,仅在性能分析要求时才升级到 lop/lom/loiErr 后缀(MapErr、FilterErr、ReduceErr),在第一个错误处停止go get github.com/samber/lo
| 包 | 导入路径 | 别名 | Go 版本要求 |
|---|---|---|---|
| 核心(不可变) | github.com/samber/lo | lo | 1.18+ |
| 并行处理 | github.com/samber/lo/parallel | lop | 1.18+ |
| 可变操作 | github.com/samber/lo/mutable | lom | 1.18+ |
| 迭代器 | github.com/samber/lo/it | loi | 1.23+ |
| SIMD(实验性) | github.com/samber/lo/exp/simd | — | 1.25+(仅 amd64) |
从 lo 开始。仅当性能分析显示瓶颈或明确需要惰性求值时,才转向其他包。
| 包 | 使用场景 | 权衡 |
|---|---|---|
lo | 所有转换操作的默认选择 | 分配新集合(安全、可预测) |
lop | 大型数据集(1000+ 项)上的 CPU 密集型工作 | Goroutine 开销;不适用于 I/O 或小型切片 |
lom | 经 pprof -alloc_objects 确认的热点路径 | 修改输入 —— 调用者必须理解副作用 |
loi | 具有链式转换的大型数据集(Go 1.23+) | 惰性求值节省内存但增加了迭代器复杂度 |
simd | 基准测试后的数值批量操作(实验性) | API 不稳定,版本间可能破坏 |
关键规则:
lop 用于 CPU 并行,而非 I/O 并发 —— 对于 I/O 扇出,请改用 errgrouplom 打破了不可变性 —— 仅在测量到分配压力时使用,切勿假设loi 通过惰性求值消除了 Map → Filter → Take 等链式调用中的中间分配samber/cc-skills-golang@golang-samber-ro 技能 + samber/ro 包有关详细的包比较和决策流程图,请参阅包指南。
// ✓ lo — 声明式,类型安全
names := lo.Map(users, func(u User, _ int) string {
return u.Name
})
// ✗ 手动 — 样板代码,易出错
names := make([]string, 0, len(users))
for _, u := range users {
names = append(names, u.Name)
}
total := lo.Reduce(
lo.Filter(orders, func(o Order, _ int) bool {
return o.Status == "paid"
}),
func(sum float64, o Order, _ int) float64 {
return sum + o.Amount
},
0,
)
byStatus := lo.GroupBy(tasks, func(t Task, _ int) string {
return t.Status
})
// map[string][]Task{"open": [...], "closed": [...]}
results, err := lo.MapErr(urls, func(url string, _ int) (Response, error) {
return http.Get(url)
})
| 错误 | 失败原因 | 修复方法 |
|---|---|---|
当 slices.Contains 存在时使用 lo.Contains | 为标准库已涵盖的操作引入了不必要的依赖 | 自 Go 1.21+ 起,优先使用 slices.Contains、slices.Sort、maps.Keys |
在 10 个项上使用 lop.Map | Goroutine 创建开销超过了转换成本 | 使用 lo.Map —— lop 的优势在约 1000+ 项的 CPU 密集型工作中才开始显现 |
假设 lo.Filter 会修改输入 | lo 默认是不可变的 —— 它返回一个新的切片 | 如果需要原地修改,请使用 lom.Filter |
在生产代码路径中使用 lo.Must | Must 在出错时会 panic —— 在测试和初始化中没问题,但在请求处理器中很危险 | 使用非 Must 变体并处理错误 |
| 在大型数据上链式调用多个急切转换 | 每个步骤都会分配一个中间切片 | 使用 loi(惰性迭代器)来避免中间分配 |
slices.Contains、slices.Sort、maps.Keys 不引入依赖。对于标准库未提供的转换(Map、Filter、Reduce、GroupBy、Chunk、Flatten),使用 lolo.Filter → lo.Map → lo.GroupBy,而不是编写嵌套循环。每个函数都是一个构建块go tool pprof 确认分配或 CPU 是瓶颈后,才从 lo 切换到 lom/loplo.MapErr 而非 lo.Map + 手动错误收集。错误变体会提前停止并清晰地传播错误lo.Must —— 在生产环境中,显式处理错误| 函数 | 功能 |
|---|---|
lo.Map | 转换每个元素 |
lo.Filter / lo.Reject | 保留 / 移除匹配谓词的元素 |
lo.Reduce | 将元素折叠为单个值 |
lo.ForEach | 带副作用的迭代 |
lo.GroupBy | 按键分组元素 |
lo.Chunk | 分割成固定大小的批次 |
lo.Flatten | 将嵌套切片展平一级 |
lo.Uniq / lo.UniqBy | 移除重复项 |
lo.Find / lo.FindOrElse | 第一个匹配项或默认值 |
lo.Contains / lo.Every / lo.Some | 成员资格测试 |
lo.Keys / lo.Values | 提取映射的键或值 |
lo.PickBy / lo.OmitBy | 过滤映射条目 |
lo.Zip2 / lo.Unzip2 | 配对/解配对两个切片 |
lo.Range / lo.RangeFrom | 生成数字序列 |
lo.Ternary / lo.If | 内联条件判断 |
lo.ToPtr / lo.FromPtr | 指针辅助函数 |
lo.Must / lo.Try | 出错时 panic / 恢复为布尔值 |
lo.Async / lo.Attempt | 异步执行 / 带退避的重试 |
lo.Debounce / lo.Throttle | 速率限制 |
lo.ChannelDispatcher | 扇出到多个通道 |
完整的函数目录(300+ 个函数),请参阅 API 参考。
关于组合模式、标准库互操作和迭代器管道,请参阅高级模式。
如果在 samber/lo 中遇到错误或意外行为,请在 github.com/samber/lo/issues 提交 issue。
samber/cc-skills-golang@golang-samber-ro 技能(samber/ro 包)samber/cc-skills-golang@golang-samber-mo 技能samber/cc-skills-golang@golang-data-structures 技能lom/lop 之前的性能分析方法,参见 samber/cc-skills-golang@golang-performance 技能每周安装量
95
代码仓库
GitHub 星标数
276
首次出现
3 天前
安全审计
安装于
opencode89
codex86
cursor86
gemini-cli86
kimi-cli85
amp85
Persona: You are a Go engineer who prefers declarative collection transforms over manual loops. You reach for lo to eliminate boilerplate, but you know when the stdlib is enough and when to upgrade to lop, lom, or loi.
Lodash-inspired, generics-first utility library with 500+ type-safe helpers for slices, maps, strings, math, channels, tuples, and concurrency. Zero external dependencies. Immutable by default.
Official Resources:
This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform.
Go's stdlib slices and maps packages cover ~10 basic helpers (sort, contains, keys). Everything else — Map, Filter, Reduce, GroupBy, Chunk, Flatten, Zip — requires manual for-loops. lo fills this gap:
interface{} casts, no reflection, compile-time checking, no interface boxing overheadlo, upgrade to lop/lom/loi only when profiling demands itErr suffixes (MapErr, FilterErr, ) that stop on first errorgo get github.com/samber/lo
| Package | Import | Alias | Go version |
|---|---|---|---|
| Core (immutable) | github.com/samber/lo | lo | 1.18+ |
| Parallel | github.com/samber/lo/parallel | lop | 1.18+ |
| Mutable | github.com/samber/lo/mutable | lom |
Start with lo. Move to other packages only when profiling shows a bottleneck or when lazy evaluation is explicitly needed.
| Package | Use when | Trade-off |
|---|---|---|
lo | Default for all transforms | Allocates new collections (safe, predictable) |
lop | CPU-bound work on large datasets (1000+ items) | Goroutine overhead; not for I/O or small slices |
lom | Hot path confirmed by pprof -alloc_objects | Mutates input — caller must understand side effects |
loi | Large datasets with chained transforms (Go 1.23+) | Lazy evaluation saves memory but adds iterator complexity |
Key rules:
lop is for CPU parallelism, not I/O concurrency — for I/O fan-out, use errgroup insteadlom breaks immutability — only use when allocation pressure is measured, never assumedloi eliminates intermediate allocations in chains like Map → Filter → Take by evaluating lazilysamber/cc-skills-golang@golang-samber-ro skill + samber/ro packageFor detailed package comparison and decision flowchart, see Package Guide.
// ✓ lo — declarative, type-safe
names := lo.Map(users, func(u User, _ int) string {
return u.Name
})
// ✗ Manual — boilerplate, error-prone
names := make([]string, 0, len(users))
for _, u := range users {
names = append(names, u.Name)
}
total := lo.Reduce(
lo.Filter(orders, func(o Order, _ int) bool {
return o.Status == "paid"
}),
func(sum float64, o Order, _ int) float64 {
return sum + o.Amount
},
0,
)
byStatus := lo.GroupBy(tasks, func(t Task, _ int) string {
return t.Status
})
// map[string][]Task{"open": [...], "closed": [...]}
results, err := lo.MapErr(urls, func(url string, _ int) (Response, error) {
return http.Get(url)
})
| Mistake | Why it fails | Fix |
|---|---|---|
Using lo.Contains when slices.Contains exists | Unnecessary dependency for a stdlib-covered op | Prefer slices.Contains, slices.Sort, maps.Keys since Go 1.21+ |
Using lop.Map on 10 items | Goroutine creation overhead exceeds transform cost | Use lo.Map — lop benefits start at ~1000+ items for CPU-bound work |
slices.Contains, slices.Sort, maps.Keys carry no dependency. Use lo for transforms the stdlib doesn't offer (Map, Filter, Reduce, GroupBy, Chunk, Flatten)lo.Filter → lo.Map → lo.GroupBy instead of writing nested loops. Each function is a building blocklo to lom/lop only after confirms allocation or CPU as the bottleneck| Function | What it does |
|---|---|
lo.Map | Transform each element |
lo.Filter / lo.Reject | Keep / remove elements matching predicate |
lo.Reduce | Fold elements into a single value |
lo.ForEach | Side-effect iteration |
lo.GroupBy | Group elements by key |
lo.Chunk |
For the complete function catalog (300+ functions), see API Reference.
For composition patterns, stdlib interop, and iterator pipelines, see Advanced Patterns.
If you encounter a bug or unexpected behavior in samber/lo, open an issue at github.com/samber/lo/issues.
samber/cc-skills-golang@golang-samber-ro skill for reactive/streaming pipelines over infinite event streams (samber/ro package)samber/cc-skills-golang@golang-samber-mo skill for monadic types (Option, Result, Either) that compose with lo transformssamber/cc-skills-golang@golang-data-structures skill for choosing the right underlying data structuresamber/cc-skills-golang@golang-performance skill for profiling methodology before switching to lom/lopWeekly Installs
95
Repository
GitHub Stars
276
First Seen
3 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode89
codex86
cursor86
gemini-cli86
kimi-cli85
amp85
ESLint迁移到Oxlint完整指南:JavaScript/TypeScript项目性能优化工具
1,700 周安装
ReduceErr| 1.18+ |
| Iterator | github.com/samber/lo/it | loi | 1.23+ |
| SIMD (experimental) | github.com/samber/lo/exp/simd | — | 1.25+ (amd64 only) |
simd| Numeric bulk ops after benchmarking (experimental) |
| Unstable API, may break between versions |
Assuming lo.Filter modifies the input | lo is immutable by default — it returns a new slice | Use lom.Filter if you explicitly need in-place mutation |
Using lo.Must in production code paths | Must panics on error — fine in tests and init, dangerous in request handlers | Use the non-Must variant and handle the error |
| Chaining many eager transforms on large data | Each step allocates an intermediate slice | Use loi (lazy iterators) to avoid intermediate allocations |
go tool pproflo.MapErr over lo.Map + manual error collection. Error variants stop early and propagate cleanlylo.Must only in tests and init — in production, handle errors explicitly| Split into fixed-size batches |
lo.Flatten | Flatten nested slices one level |
lo.Uniq / lo.UniqBy | Remove duplicates |
lo.Find / lo.FindOrElse | First match or default |
lo.Contains / lo.Every / lo.Some | Membership tests |
lo.Keys / lo.Values | Extract map keys or values |
lo.PickBy / lo.OmitBy | Filter map entries |
lo.Zip2 / lo.Unzip2 | Pair/unpair two slices |
lo.Range / lo.RangeFrom | Generate number sequences |
lo.Ternary / lo.If | Inline conditionals |
lo.ToPtr / lo.FromPtr | Pointer helpers |
lo.Must / lo.Try | Panic-on-error / recover-as-bool |
lo.Async / lo.Attempt | Async execution / retry with backoff |
lo.Debounce / lo.Throttle | Rate limiting |
lo.ChannelDispatcher | Fan-out to multiple channels |