深入浅析Rust collect()
作者:Ivanqhz
collect()是Rust迭代器的终端操作(consuming adaptor),它把惰性迭代器"消费"掉,将沿途产生的所有元素收集到一个具体的集合类型中,这篇文章给大家介绍Rust collect() 的相关知识,感兴趣的朋友一起看看吧
.collect()浅析
let json_movies: Vec<_> = movies.iter().map(|m| m.to_json()).collect();
.collect() 是 Rust 迭代器的终端操作(consuming adaptor),它把惰性迭代器"消费"掉,将沿途产生的所有元素收集到一个具体的集合类型中。
一、类比理解
迭代器(Iterator) ≈ 工厂流水线 .iter() ≈ 启动传送带 .map(...) ≈ 每个零件经过加工工位(还未实际生产) .collect() ≈ 最终打包成箱子,触发整条流水线运转
关键点:在 .collect() 被调用之前,整条迭代器链都是惰性的,不会执行任何实际操作。
二、逐层拆解
let movies = dm.get_movies_by_genre(&query.genre, size, sort_by); // ① Vec<&Movie>
let json_movies: Vec<_> = movies
.iter() // ② 创建迭代器,元素类型 &Movie
.map(|m| m.to_json()) // ③ 对每个 &Movie 调用 to_json() → MovieJson
.collect(); // ④ 把所有 MovieJson 收集到 Vec<MovieJson>
①movies— 原始数据
// get_movies_by_genre 返回:
Vec<&Movie> = [
&Movie { movie_id: 1, title: "Toy Story", ... },
&Movie { movie_id: 2, title: "Jumanji", ... },
&Movie { movie_id: 3, title: "Grumpier Old Men", ... },
]
②.iter()— 创建迭代器
// .iter() 返回一个 Iter<&Movie>,它实现了 Iterator trait // 类型:impl Iterator<Item = &&Movie> // 等价于手写: let mut iter = movies.iter(); // 此时什么都没做,只是一个"蓝图"
③.map(|m| m.to_json())— 转换元素
// .map() 返回另一个迭代器 Map<Iter<&Movie>, closure> // 类型:impl Iterator<Item = MovieJson> // 此时仍然什么都没做!map 只是记录了"当需要下一个元素时,执行这个闭包"
④.collect()— 触发执行 & 收集结果
// .collect() 遍历迭代器,对每个元素执行 map 闭包,
// 把结果 push 进一个新 Vec,返回这个 Vec
// 类型:Vec<MovieJson>
// 等价于手写:
let mut json_movies = Vec::new();
for m in movies.iter() {
json_movies.push(m.to_json());
}三、详细例子
输入数据
// 假设 dm.get_movies_by_genre("Comedy", 3, "rating") 返回:
movies = [
&Movie { movie_id: 1, title: "Toy Story", ... },
&Movie { movie_id: 2, title: "Jumanji", ... },
&Movie { movie_id: 3, title: "Grumpier", ... },
]
collect() 执行的内部过程
循环第 1 轮:
iter.next() → Some(&&Movie { movie_id: 1, ... }) ← .iter() 取出第1个
|m| m.to_json() ← map 闭包执行
→ MovieJson { movie_id: 1, title: "Toy Story", ... } ← to_json() 转换
→ vec.push(MovieJson { movie_id: 1, ... }) ← 推入 Vec
循环第 2 轮:
iter.next() → Some(&&Movie { movie_id: 2, ... })
→ MovieJson { movie_id: 2, title: "Jumanji", ... }
→ vec.push(...)
循环第 3 轮:
iter.next() → Some(&&Movie { movie_id: 3, ... })
→ MovieJson { movie_id: 3, title: "Grumpier", ... }
→ vec.push(...)
循环第 4 轮:
iter.next() → None ← 迭代器耗尽,停止
最终:vec = [
MovieJson { movie_id: 1, ... },
MovieJson { movie_id: 2, ... },
MovieJson { movie_id: 3, ... },
]最终 JSON 输出
[
{ "movieId": 1, "title": "Toy Story", "releaseYear": 1995, ... },
{ "movieId": 2, "title": "Jumanji", "releaseYear": 1995, ... },
{ "movieId": 3, "title": "Grumpier Old Men", "releaseYear": 1995, ... }
]四、Vec<_>类型推导
let json_movies: Vec<_> = movies.iter().map(|m| m.to_json()).collect(); // ^^^^^^^ // Vec<_> 告诉编译器"我需要一个 Vec" // _ 表示"元素类型你自己推导"
编译器看到:
movies.iter()→ 元素是&&Movie.map(|m| m.to_json())→to_json()返回MovieJson.collect()→ 收集进Vec<_>→_推导为MovieJson
最终类型:Vec<MovieJson>
等价写法
let json_movies: Vec<MovieJson> = movies.iter().map(|m| m.to_json()).collect(); // 显式类型 let json_movies = movies.iter().map(|m| m.to_json()).collect::<Vec<_>>(); // turbofish 语法
五、collect 可以收集到多种集合类型
let v: Vec<_> = (0..5).collect(); // [0, 1, 2, 3, 4]
let h: HashSet<_> = (0..5).collect(); // {0, 1, 2, 3, 4} (无序)
let s: String = ['h','e','l','l','o'].iter().collect(); // "hello"
let m: HashMap<_, _> = [("a",1), ("b",2)].iter().cloned().collect(); // {"a":1, "b":2}
同一行 .collect() 能产出 Vec、HashSet、HashMap 等不同集合——完全由左边变量的类型注解决定。
六、为什么需要 collect()?
| 没有 collect | 有 collect |
|---|---|
| 迭代器是惰性的,数据还没实际生成 | 立即执行所有计算,产生具体集合 |
类型是 impl Iterator<Item=MovieJson> | 类型是 Vec<MovieJson> |
不能传给 HttpResponse::Ok().json() | .json() 只接受具体的可序列化类型 |
// ❌ 错误:Iterator 本身不能被序列化 let iter = movies.iter().map(|m| m.to_json()); HttpResponse::Ok().json(iter); // 编译失败! // ✅ 正确:collect 把迭代器变成 Vec,Vec 可序列化 let vec: Vec<_> = movies.iter().map(|m| m.to_json()).collect(); HttpResponse::Ok().json(vec); // 编译通过
七、完整数据流图
DataManager
│
└─ get_movies_by_genre("Comedy", 3, "rating")
│
▼
Vec<&Movie> ← 原始内部数据
│
│ .iter()
▼
Iter<&Movie> ← 惰性迭代器(蓝图)
│
│ .map(|m| m.to_json())
▼
Map<Iter, fn> ← 惰性迭代器(蓝图 + 转换逻辑)
│
│ .collect() ←────── 触发执行!遍历所有元素
▼
Vec<MovieJson> ← 具体集合,可被 serde 序列化
│
│ HttpResponse::Ok().json(...)
▼
HTTP Response Body:
[{"movieId":1,...}, {"movieId":2,...}, {"movieId":3,...}]到此这篇关于深入浅析Rust collect() 的文章就介绍到这了,更多相关Rust collect()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
