集合
所有集合通用规则
iter():只读,返回不可变引用,原集合不受影响iter_mut():可修改,返回可变引用,原集合不受影响into_iter():转移所有权,返回元素本身,原集合被消耗map/filter仅能用于迭代器,不能直接用于集合本身- 惰性求值、零成本抽象 完全一致
| 方法 | 返回迭代器 | 元素类型 | 所有权 | 原集合 | 适用场景 |
|---|---|---|---|---|---|
iter() | Iter<'a, T> | &T | 不可变引用 | 可用 | 只读遍历元素 |
iter_mut() | IterMut<'a, T> | &mut T | 可变引用 | 可用 | 修改集合元素(极少用) |
into_iter() | IntoIter<T> | T | 所有权转移 | 销毁 | 拿走所有元素所有权 |
问题:
1、为啥 Option & Result 不需要iter,可以直接进行组合器调用?
**Vec/HashSet/HashMap 是「多元素集合」,自身没有实现组合器,必须用 iter() 生成迭代器才能调用 map/filter;
Option/Result 是「0~1 个元素的值包装器」,它们**自己直接实现了 map/and_then 等组合器 **,和迭代器 Iterator 没有任何关系 **,所以根本不需要 iter()。
集合类型(Vec/HashSet/BTreeMap)
- 身份:多元素容器(存放 N 个值,N ≥ 0)
- 特性:本身不实现
Iterator,也没有自带map/filter方法 - 必须:调用
iter()/into_iter()生成一个迭代器,再用迭代器的组合器
Option / Result
- 身份:单子 (Monad) / 值包装器(最多存 1 个值)
Option<T>:要么有值Some(T),要么无值NoneResult<T, E>:要么成功Ok(T),要么失败Err(E)
- 特性:自己实现了专属的
map/and_then/filter方法 - 无需:任何迭代器,直接调用组合器
源码实锤:组合器到底来自哪里?
Option 直接自带 map,Rust 标准库中 Option 的 map 方法源码:
// Option 自己的 impl 块,直接实现 map!
impl<T> Option<T> {
pub fn map<F, U>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> U,
{
match self {
Some(x) => Some(f(x)), // 有值就处理
None => None, // 无值直接返回
}
}
}
Option::map 是自身方法,处理内部唯一的值。
集合的 map 来自迭代器(必须先 iter ())
Vec 自身没有 map 方法,map 是 Iterator trait 提供的:
// Vec 本身没有 map!
// 你调用的 map 来自这里:
impl<I: Iterator> Iterator for I {
fn map<B, F>(self, f: F) -> Map<Self, F> { ... }
}
语义对比:同样叫 map,行为天差地别
| 调用方式 | 来源 | 处理对象 | 行为逻辑 |
|---|---|---|---|
vec.iter().map() | 迭代器 Iterator | 多个元素 | 遍历所有元素,逐个处理 |
option.map() | Option 自身 | 0/1 个元素 | 只处理内部那个值,无值则跳过 |
result.map() | Result 自身 | 1 个成功值 / 错误 | 只处理成功值,错误直接透传 |
// 1. 集合:必须 iter(),处理多个元素
let v = vec![1,2,3];
let v2 = v.iter().map(|x| x*2).collect::<Vec<_>>(); // [2,4,6]
// 2. Option:直接 map,处理单个值
let some_num = Some(5);
let opt2 = some_num.map(|x| x*2); // Some(10)
let none_num: Option<i32> = None;
let opt3 = none_num.map(|x| x*2); // None(直接跳过)
// 3. Result:直接 map,处理成功值
let ok_val: Result<i32, &str> = Ok(10);
let res2 = ok_val.map(|x| x*2); // Ok(20)
let err_val: Result<i32, &str> = Err("错误");
let res3 = err_val.map(|x| x*2); // Err("错误")(不处理)