Rust collect() 浅析

.collect() 浅析

rust 复制代码
let json_movies: Vec<_> = movies.iter().map(|m| m.to_json()).collect();

.collect() 是 Rust 迭代器的终端操作 (consuming adaptor),它把惰性迭代器"消费"掉,将沿途产生的所有元素收集到一个具体的集合类型中。


一、类比理解

复制代码
迭代器(Iterator)  ≈  工厂流水线
  .iter()            ≈  启动传送带
  .map(...)          ≈  每个零件经过加工工位(还未实际生产)
  .collect()         ≈  最终打包成箱子,触发整条流水线运转

关键点 :在 .collect() 被调用之前,整条迭代器链都是惰性的,不会执行任何实际操作。


二、逐层拆解

rust 复制代码
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 --- 原始数据

rust 复制代码
// 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() --- 创建迭代器

rust 复制代码
// .iter() 返回一个 Iter<&Movie>,它实现了 Iterator trait
// 类型:impl Iterator<Item = &&Movie>

// 等价于手写:
let mut iter = movies.iter();  // 此时什么都没做,只是一个"蓝图"

.map(|m| m.to_json()) --- 转换元素

rust 复制代码
// .map() 返回另一个迭代器 Map<Iter<&Movie>, closure>
// 类型:impl Iterator<Item = MovieJson>

// 此时仍然什么都没做!map 只是记录了"当需要下一个元素时,执行这个闭包"

.collect() --- 触发执行 & 收集结果

rust 复制代码
// .collect() 遍历迭代器,对每个元素执行 map 闭包,
// 把结果 push 进一个新 Vec,返回这个 Vec
// 类型:Vec<MovieJson>

// 等价于手写:
let mut json_movies = Vec::new();
for m in movies.iter() {
    json_movies.push(m.to_json());
}

三、详细例子

输入数据

rust 复制代码
// 假设 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 输出

json 复制代码
[
  { "movieId": 1, "title": "Toy Story", "releaseYear": 1995, ... },
  { "movieId": 2, "title": "Jumanji", "releaseYear": 1995, ... },
  { "movieId": 3, "title": "Grumpier Old Men", "releaseYear": 1995, ... }
]

四、Vec<_> 类型推导

rust 复制代码
let json_movies: Vec<_> = movies.iter().map(|m| m.to_json()).collect();
//               ^^^^^^^
//               Vec<_> 告诉编译器"我需要一个 Vec"
//               _ 表示"元素类型你自己推导"

编译器看到:

  1. movies.iter() → 元素是 &&Movie
  2. .map(|m| m.to_json())to_json() 返回 MovieJson
  3. .collect() → 收集进 Vec<_>_ 推导为 MovieJson

最终类型Vec<MovieJson>

等价写法

rust 复制代码
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 可以收集到多种集合类型

rust 复制代码
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() 能产出 VecHashSetHashMap 等不同集合------完全由左边变量的类型注解决定。


六、为什么需要 collect()?

没有 collect 有 collect
迭代器是惰性的,数据还没实际生成 立即执行所有计算,产生具体集合
类型是 impl Iterator<Item=MovieJson> 类型是 Vec<MovieJson>
不能传给 HttpResponse::Ok().json() .json() 只接受具体的可序列化类型
rust 复制代码
// ❌ 错误: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,...}]
相关推荐
cxr8288 小时前
HyperMind Lab M1 架构地基 Implementation Plan <二>
开发语言·人工智能·架构
卷无止境8 小时前
FastAPI 的 WebSocket 装了些什么
后端·python·fastapi
特立独行的猫a8 小时前
Tauri v2的Rust应用 → HarmonyOS(鸿蒙 PC)移植30分钟速成指南
开发语言·rust·harmonyos·tauri·移植·鸿蒙pc
迷迭香yy8 小时前
大宗交易折溢价因子怎么挖掘本地化Python全流程实战
开发语言·人工智能·python
xieliyu.8 小时前
UPD协议结构以及开发中注意事项
java·开发语言·笔记·java-ee
AINative软件工程8 小时前
Agent 上下文账本工程:别让工具结果把 128K 窗口塞成垃圾场
后端·架构·ai编程
卷无止境8 小时前
FastAPI 的 Request 类装了什么
后端·python
Yweir8 小时前
AI大模型开发-Python介绍、版本说明
开发语言·人工智能·python
程序员爱钓鱼8 小时前
Rust 方法 Method详解:self、方法调用与API设计
后端·面试·rust
橙子家8 小时前
MSDTC(微软分布式事务处理协调器)对系统稳定性的影响
后端