
golang-samber-lo
热门Golang 的函数式编程辅助工具库,基于 samber/lo — 500 多个类型安全的泛型函数,用于切片、映射、通道、字符串、数学、元组和并发(Map、Filter、Reduce、GroupBy、Chunk、Flatten、Find、Uniq 等)。核心不可变包(lo)、并发变体(lo/parallel 即 lop)、原地修改(lo/mutable 即 lom)、惰性迭代器(lo/it 即 loi,Go 1.23+)以及实验性 SIMD(lo/exp/simd)。适用于使用或采用 samber/lo 时、代码库导入 github.com/samber/lo 时、或在 Go 中实现函数式风格数据转换时。不适用于流式管道(→ 参见 `samber/cc-skills-golang@golang-samber-ro` 技能)。
Golang 的函数式编程辅助工具库,基于 samber/lo — 500 多个类型安全的泛型函数,用于切片、映射、通道、字符串、数学、元组和并发(Map、Filter、Reduce、GroupBy、Chunk、Flatten、Find、Uniq 等)。核心不可变包(lo)、并发变体(lo/parallel 即 lop)、原地修改(lo/mutable 即 lom)、惰性迭代器(lo/it 即 loi,Go 1.23+)以及实验性 SIMD(lo/exp/simd)。适用于使用或采用 samber/lo 时、代码库导入 github.com/samber/lo 时、或在 Go 中实现函数式风格数据转换时。不适用于流式管道(→ 参见 `samber/cc-skills-golang@golang-samber-ro` 技能)。
角色设定: 你是一位 Go 工程师,更倾向于声明式集合转换而非手动循环。你使用 lo 来消除样板代码,但你知道何时标准库已足够,以及何时升级到 lop、lom 或 loi。
samber/lo — Go 函数式工具库
受 Lodash 启发、以泛型为先的工具库,提供 500 多个类型安全的辅助函数,用于切片、映射、字符串、数学、通道、元组和并发。零外部依赖。默认不可变。
官方资源:
本技能并非详尽无遗。请参考库文档和代码示例获取更多信息。Context7 可作为发现平台提供帮助。对于 Go 包文档、版本、符号和已知漏洞,→ 参见 samber/cc-skills-golang@golang-pkg-go-dev 技能。
为什么选择 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 |
大数据集上的 CPU 密集型工作(1000+ 项) | 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;自 Go 1.23+ 起,当需要键切片时使用 slices.Collect(maps.Keys(m)) |
对 10 个元素使用 lop.Map |
Goroutine 创建开销超过转换成本 | 使用 lo.Map——lop 的优势在 CPU 密集型工作中约 1000+ 项时才开始体现 |
假设 lo.Filter 会修改输入 |
lo 默认不可变——它返回一个新切片 |
如果明确需要原地修改,使用 lom.Filter |
在生产代码路径中使用 lo.Must |
Must 在出错时 panic——在测试和 init 中没问题,但在请求处理程序中很危险 |
使用非 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+ 手动错误收集。错误变体会提前停止并干净地传播 - 仅在测试和 init 中使用
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 提交问题。
交叉引用
- → 参见
samber/cc-skills-golang@golang-samber-ro技能,了解无限事件流上的响应式/流式管道(samber/ro包) - → 参见
samber/cc-skills-golang@golang-samber-mo技能,了解可与 lo 转换组合的单子类型(Option、Result、Either) - → 参见
samber/cc-skills-golang@golang-data-structures技能,了解如何选择正确的底层数据结构 - → 参见
samber/cc-skills-golang@golang-performance技能,了解在切换到lom/lop之前的分析方法





