golang-samber-lo

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` 技能)。

2261Star
150Fork
更新于 2026/6/6
SKILL.md
只读
名称
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` 技能)。

角色设定: 你是一位 Go 工程师,更倾向于声明式集合转换而非手动循环。你使用 lo 来消除样板代码,但你知道何时标准库已足够,以及何时升级到 loplomloi

samber/lo — Go 函数式工具库

受 Lodash 启发、以泛型为先的工具库,提供 500 多个类型安全的辅助函数,用于切片、映射、字符串、数学、通道、元组和并发。零外部依赖。默认不可变。

官方资源:

本技能并非详尽无遗。请参考库文档和代码示例获取更多信息。Context7 可作为发现平台提供帮助。对于 Go 包文档、版本、符号和已知漏洞,→ 参见 samber/cc-skills-golang@golang-pkg-go-dev 技能。

为什么选择 samber/lo

Go 标准库的 slicesmaps 包仅覆盖约 10 个基本辅助函数(排序、包含、键)。其他所有功能——Map、Filter、Reduce、GroupBy、Chunk、Flatten、Zip——都需要手动 for 循环。lo 填补了这一空白:

  • 类型安全的泛型 — 无需 interface{} 类型断言,无反射,编译时检查,无接口装箱开销
  • 默认不可变 — 返回新集合,安全用于并发读取,更易于推理
  • 可组合 — 函数接收并返回切片/映射,因此无需包装类型即可链式调用
  • 零依赖 — 仅依赖 Go 标准库,无传递依赖风险
  • 渐进式复杂度 — 从 lo 开始,仅在性能分析需要时升级到 lop/lom/loi
  • 错误变体 — 大多数函数带有 Err 后缀(MapErrFilterErrReduceErr),在第一个错误时停止

安装

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 扇出,请使用 errgroup
  • lom 打破不可变性——仅在测量到分配压力时使用,切勿假设
  • 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(惰性迭代器)避免中间分配

最佳实践

  1. 优先使用标准库(如果可用)slices.Containsslices.Sort(Go 1.21+)无依赖;maps.Keys 是 Go 1.23+ 并返回迭代器,因此当需要切片时使用 slices.Collect(maps.Keys(m))。对于标准库未提供的转换(Map、Filter、Reduce、GroupBy、Chunk、Flatten),使用 lo
  2. 组合 lo 函数 — 链式调用 lo.Filterlo.Maplo.GroupBy,而不是编写嵌套循环。每个函数都是一个构建块
  3. 先分析再优化 — 仅在 go tool pprof 确认分配或 CPU 是瓶颈后,才从 lo 切换到 lom/lop
  4. 使用错误变体 — 优先使用 lo.MapErr 而非 lo.Map + 手动错误收集。错误变体会提前停止并干净地传播
  5. 仅在测试和 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 之前的分析方法