Go slices.Collect 如何把迭代器结果收集成切片
来源:17golang原创
时间:2026-09-12 16:40:27 432浏览 收藏
在 Go 1.23 以后,如果手里已经有一个 iter.Seq[E],想把它变成普通切片,优先记住这一句:result := slices.Collect(seq)。它会消费序列并返回一个新的 []E;序列为空时结果是 nil。如果序列长度事先已知,而且这段代码在高频路径上,则可以自己 make 一个带容量的切片再 append,把容量策略掌握在调用方手里。
slices.Collect是 Go 1.23 新增的迭代器收集函数,参数类型是iter.Seq[E]。- 它返回新的切片头和底层存储;但元素本身仍按 Go 的赋值规则处理,不会递归深拷贝指针指向的对象。
- 不知道序列长度时用 Collect 最省心;知道数量且关注扩容时,用预分配切片手动收集。
从切片或自定义序列开始
slices.Values 可以把已有切片暴露成只产生元素的 iter.Seq。这正好适合演示 Collect 的边界:输入仍然是原切片,输出是另一份切片。
package main
import (
"fmt"
"slices"
)
func main() {
// Values 只提供迭代视图,不在这里创建结果切片。
source := []string{"Go", "iterator", "collect"}
result := slices.Collect(slices.Values(source))
// 修改结果的切片槽位,不会改写 source 的对应元素。
result[0] = "Golang"
fmt.Println(source)
fmt.Println(result)
}

如果数据不是现成切片,也可以自己返回一个序列。迭代器通过 yield 把值交给调用方;一旦 yield 返回 false,生产者应停止继续提供数据。
slices.Collect 到底收集了什么
Collect 的签名是 func Collect[E any](seq iter.Seq[E]) []E。它解决的是“把 push 风格的序列落成切片”,不是排序、去重或深拷贝。下面这个例子同时展示自定义序列和空序列的结果:
package main
import (
"fmt"
"iter"
"slices"
)
func evenNumbers() iter.Seq[int] {
return func(yield func(int) bool) {
for n := 0; n
这里的 values 是普通的 []int,可以交给需要切片的旧接口;empty 是 nil,所以不要只用长度判断“有没有分配过”,若业务区分 nil 与空切片,应把这个约定写进接口说明。
长度已知时,为什么还要手动预分配
Collect 不要求序列提供长度提示,因此调用方无法通过它直接声明“结果一定有 N 个元素”。内部收集需要随着元素到达追加,切片容量可能按运行时策略增长。多数业务代码不需要关心这个细节;但批量转换、热循环或大结果集里,已知上限时可以显式预留:
func collectWithCapacity(seq iter.Seq[string], size int) []string {
// 只预留容量,长度从零开始,避免把未填充槽位当成结果。
result := make([]string, 0, size)
for value := range seq {
// append 按实际产出数量增长长度;size 只是容量提示。
result = append(result, value)
}
return result
}
| 场景 | 建议 | 要记住的代价 |
|---|---|---|
| 序列长度未知 | slices.Collect(seq) | 代码短,容量交给运行时增长 |
| 数量有可靠上限 | make([]E, 0, n) 加 append | 上限估错会多占容量或仍需扩容 |
| 元素含指针或引用 | 按需复制元素指向的数据 | Collect 不是深拷贝 |

落地时最容易忽略的三个边界
第一,Collect 只建立结果切片,不会把元素内部的指针对象复制一份;例如元素是 *Config,结果里的指针仍可能指向同一份 Config。第二,空序列的 nil 结果在 JSON、接口约定或比较逻辑里可能和 []E{} 不同,需要按 API 契约决定是否归一化。第三,Collect 是消费序列的动作,自定义序列里应在停止信号到达后释放或终止自己的生产逻辑,不能继续无条件生成数据。
相关问题
Collect 能不能直接把 map 变成切片?
不能直接把 map 作为 iter.Seq 传入。可以先用 maps.Keys 或 maps.Values 得到序列,再 Collect;map 遍历顺序仍不应当被当成稳定排序。
Collect 会自动排序吗?
不会。需要排序时使用 slices.Sorted(seq) 或先 Collect 再调用合适的排序函数,别把收集和排序的职责混在一起。
Go 1.22 项目能调用 slices.Collect 吗?
不能按 Go 1.22 的标准库假设直接使用;该 API 随 Go 1.23 加入。旧项目可以保留手写 for range 加 append,或先升级工具链并确认 go.mod 与 CI 环境一致。
因此,普通迭代器结果落地时选 slices.Collect,已知规模且在意分配时用预分配 append;真正需要深拷贝或稳定顺序,则另外明确实现,别把它们误认为 Collect 的默认行为。
-
267 收藏
-
369 收藏
-
496 收藏
-
202 收藏
-
344 收藏
-
413 收藏
-
423 收藏
-
478 收藏
-
468 收藏
-
163 收藏
-
408 收藏
-
331 收藏
-
426 收藏
-
313 收藏
-
475 收藏
-
232 收藏
-
108 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习