关于 golang-samber-lo
介绍 samber/lo 的 Go 技能;该库基于泛型,提供声明式集合转换及常用操作,帮助工程师选择合适的函数和扩展包,并说明何时优先使用标准库。
主要功能
- 01切片与映射的泛型函数
- 02转换、筛选、归约与分组数据
- 03返回错误的函数变体
- 04并行、可变与迭代器包
- 05标准库选择与性能分析指南
适用场景
- 01替代繁琐的集合循环代码
- 02组合数据转换流水线
- 03分析性能后选择惰性或并行操作
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ samber/ cc-skills-golang --skill golang-samber-lo安装后在 Claude Code 中输入/golang-samber-lo确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonreferences/advanced-patterns.mdapi-reference.mdpackage-guide.md详细介绍
角色: 你是一名 Go 工程师,更喜欢使用声明式集合转换,而不是手动编写循环。你会使用 lo 来消除样板代码,但也知道什么时候标准库就够用,什么时候该升级到 lop、lom 或 loi。
samber/lo — Go 函数式工具库
受 Lodash 启发、以泛型为先的工具库,提供 500 多个类型安全的辅助函数,涵盖切片、映射、字符串、数学、通道、元组和并发。零外部依赖。默认不可变。
官方资源:
本技能并未涵盖所有内容,更多信息请参阅库文档和代码示例:
- 如需查看 Go 包文档、符号、版本、导入方和已知漏洞,→ 请参阅
samber/cc-skills-golang@golang-pkg-go-dev技能(godig),查询 Go 包信息时优先于 Context7。 - 如需在自己的代码中了解此库的用法(定义、调用位置、诊断信息),→ 请参阅
samber/cc-skills-golang@golang-gopls技能(gopls)。 - 对于未收录在 pkg.go.dev 上的文档,可将 Context7 作为备用方案。
为什么选择 samber/lo
Go 标准库的 slices 和 maps 包涵盖约 10 个基本辅助函数(排序、包含判断、键)。其他所有操作——Map、Filter、Reduce、GroupBy、Chunk、Flatten、Zip——都需要手动编写 for 循环。lo 填补了这一空白:
- 类型安全的泛型 — 无需
interface{}类型转换,无需反射,可在编译时检查,无接口装箱开销 - 默认不可变 — 返回新的集合,可安全并发读取,更易于理解
- 可组合 — 函数接收并返回切片/映射,因此可以直接串联,无需包装类型
- 零依赖 — 仅使用 Go 标准库,无传递依赖风险
- 渐进式复杂度 — 从
lo开始,仅在性能分析表明有需要时才升级到lop/lom/loi - 错误变体 — 大多数函数都有带
Err后缀的版本(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会破坏不可变性 — 仅在测得分配压力时使用,切勿想当然地使用- 对
Map → Filter → Take这样的链式操作,loi通过惰性求值消除中间分配 - 对无限事件流进行响应式/流式处理时,→ 请参阅
samber/cc-skills-golang@golang-samber-ro技能和samber/ro包
有关详细的包对比和决策流程图,请参阅包指南。
核心模式
转换切片
// ✓ 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,
)
GroupBy
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;需要键切片时,Go 1.23+ 使用 slices.Collect(maps.Keys(m)) |
对 10 个元素使用 lop.Map | 创建 Goroutine 的开销超过转换成本 | 使用 lo.Map——对于 CPU 密集型工作,lop 从约 1000 个元素起才有优势 |
认为 lo.Filter 会修改输入 | lo 默认不可变——它会返回一个新切片 | 如果确实需要原地修改,请使用 lom.Filter |
在生产代码路径中使用 lo.Must | Must 遇到错误会触发 panic——在测试和初始化代码中没问题,但在请求处理程序中很危险 | 使用非 Must 变体并处理错误 |
| 在大型数据上连续执行多个急切转换 | 每一步都会分配一个中间切片 | 使用 loi(惰性迭代器)以避免分配中间切片 |
最佳实践
- 有标准库可用时优先使用标准库——
slices.Contains和slices.Sort(Go 1.21+)无需依赖;maps.Keys需要 Go 1.23+,并返回一个迭代器,因此需要切片时请使用slices.Collect(maps.Keys(m))。对于标准库未提供的转换(Map、Filter、Reduce、GroupBy、Chunk、Flatten),请使用lo - 组合使用 lo 函数——将
lo.Filter→lo.Map→lo.GroupBy串联起来,而不是编写嵌套循环。每个函数都是一个构建模块 - 先分析性能,再优化——只有在
go tool pprof确认分配或 CPU 是瓶颈后,才从lo切换到lom/lop - 使用错误处理变体——优先使用
lo.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 中遇到 Bug 或意外行为,请在 github.com/samber/lo/issues 提交问题。
交叉引用
- → 有关对无限事件流进行响应式 / 流式处理的流水线,请参阅
samber/cc-skills-golang@golang-samber-roskill(samber/ro包) - → 有关可与 lo 转换组合使用的单子类型(Option、Result、Either),请参阅
samber/cc-skills-golang@golang-samber-moskill - → 有关如何选择合适的底层数据结构,请参阅
samber/cc-skills-golang@golang-data-structuresskill - → 有关切换到
lom/lop前的性能分析方法,请参阅samber/cc-skills-golang@golang-performanceskill
评论
支持 Markdown