Module core::option 1.0.0[−][src]
Expand description
可选值。
类型 Option 表示一个可选值: 每个 Option 均为 Some 并包含一个值,或者为 None,但不包含。
Option 类型在 Rust 代码中非常常见,因为它们有许多用途:
- 初始值
- 未在整个输入范围内定义的函数的返回值 (部分函数)
- 返回值,用于报告否则将报告简单错误的错误,其中错误返回
None - 可选的结构体字段
- 可借用或 “taken” 的结构体字段
- 可选函数参数
- 可空指针
- 从困难的情况中交换东西
通常将 Option 与模式匹配配对,以查询值的存在并采取措施,始终考虑 None 的情况。
fn divide(numerator: f64, denominator: f64) -> Option<f64> { if denominator == 0.0 { None } else { Some(numerator / denominator) } } // 函数的返回值是一个选项 let result = divide(2.0, 3.0); // 模式匹配以获取值 match result { // 该划分有效 Some(x) => println!("Result: {}", x), // 划分无效 None => println!("Cannot divide by 0"), }Run
选项和指针 (“nullable” 指针)
Rust 的指针类型必须始终指向有效位置。没有 “null” 引用。相反, Rust 有可选指针,例如可选的拥有所有权的 box, Option<Box<T>>.
以下示例使用 Option 创建 i32 的可选 box。
注意,为了使用内部的 i32 值,check_optional 函数首先需要使用模式匹配来确定 box 是否有值 (即它是 Some(...)) 或没有 (None)。
let optional = None; check_optional(optional); let optional = Some(Box::new(9000)); check_optional(optional); fn check_optional(optional: Option<Box<i32>>) { match optional { Some(p) => println!("has value {}", p), None => println!("has no value"), } }Run
Representation
Rust 保证优化以下 T 类型,以使 Option<T> 具有与 T 相同的大小:
Box<U>&U&mut Ufn,extern "C" fnnum::NonZero*ptr::NonNull<U>#[repr(transparent)]结构体围绕此列表中的一种。
这称为 “空指针优化” 或 NPO。
对于上述情况,可以进一步保证,可以从 T 到 Option<T> 的所有有效值以及从 Some::<T>(_) 到 T 的所有有效值 mem::transmute (但是将 None::<T> 转换为 T 是未定义的行为)。
方法概述
除了使用模式匹配,Option 还提供了多种不同的方法。
查询变量
如果 Option 分别为 Some 或 None,则 is_some 和 is_none 方法返回 true。
用于处理引用的适配器
as_ref从&Option<T>转换为Option<&T>as_mut从&mut Option<T>转换为Option<&mut T>as_deref从&Option<T>转换为Option<&T::Target>as_deref_mut从&mut Option<T>转换为Option<&mut T::Target>as_pin_ref从Pin<&Option<T>>转换为Option<Pin<&T>>as_pin_mut从Pin<&mut Option<T>>转换为Option<Pin<&mut T>>
提取包含的值
这些方法提取 Option<T> 中包含的值,当它是 Some 成员时。如果 Option 为 None:
expect一个提供自定义消息的 panicsunwrap带有通用消息的 panicsunwrap_or返回提供的默认值unwrap_or_default返回类型T的默认值 (必须实现Defaulttrait)unwrap_or_else返回对提供的函数求值的结果
转换包含的值
ok_or使用提供的默认err值将Some(v)转换为Ok(v),并将None转换为Err(err)ok_or_else使用提供的函数将Some(v)转换为Ok(v),并将None转换为Err的值transpose将Result的Option转换为Option的Result
这些方法改变了 Some 成员:
filter如果Option是Some(t),则在包含的值t上调用提供的谓词函数,如果函数返回true,则返回Some(t); 否则,返回Noneflatten从一个嵌套中删除一层Option<Option<T>>map通过将提供的函数应用于Some的包含值并保持None值不变,将Option<T>转换为Option<U>
这些方法将 Option<T> 转换为可能不同类型 U 的值:
map_or将提供的函数应用于Some的包含值,如果Option是,则返回提供的默认值Nonemap_or_else将提供的函数应用于Some的包含值,或者如果Option是None,则返回评估提供的回退函数的结果
zip如果self为Some(s)且提供的Option值为Some(o),则返回Some((s, o)); 否则,返回Nonezip_with如果self为Some(s)且提供的Option值为Some(o),则调用提供的函数f并返回Some(f(s, o)); 否则,返回None
布尔运算符
这些方法将 Option 视为布尔值,其中 Some 的作用类似于 true,而 None 的作用类似于 false。这些方法有两类: 一类以 Option 作为输入,一类以函数作为输入 (延迟评估)。
and、or 和 xor 方法将另一个 Option 作为输入,并生成一个 Option 作为输出。只有 and 方法可以生成具有与 Option<T> 不同的内部类型 U 的 Option<U> 值。
| method | self | input | output |
|---|---|---|---|
and | None | (ignored) | None |
and | Some(x) | None | None |
and | Some(x) | Some(y) | Some(y) |
or | None | None | None |
or | None | Some(y) | Some(y) |
or | Some(x) | (ignored) | Some(x) |
xor | None | None | None |
xor | None | Some(y) | Some(y) |
xor | Some(x) | None | Some(x) |
xor | Some(x) | Some(y) | None |
and_then 和 or_else 方法将函数作为输入,并且仅在需要产生新值时才评估函数。只有 and_then 方法可以生成具有与 Option<T> 不同的内部类型 U 的 Option<U> 值。
| method | self | function input | function result | output |
|---|---|---|---|---|
and_then | None | (not provided) | (not evaluated) | None |
and_then | Some(x) | x | None | None |
and_then | Some(x) | x | Some(y) | Some(y) |
or_else | None | (not provided) | None | None |
or_else | None | (not provided) | Some(y) | Some(y) |
or_else | Some(x) | (not provided) | (not evaluated) | Some(x) |
这是在方法调用管道中使用 and_then 和 or 等方法的示例。管道的早期阶段通过不变的失败值 (None),并继续处理成功值 (Some)。
最后,如果 or 收到 None,它会替换一条错误消息。
let mut bt = BTreeMap::new(); bt.insert(20u8, "foo"); bt.insert(42u8, "bar"); let res = vec![0u8, 1, 11, 200, 22] .into_iter() .map(|x| { // `checked_sub()` 出错时返回 `None` x.checked_sub(1) // 与 `checked_mul()` 相同 .and_then(|x| x.checked_mul(2)) // `BTreeMap::get` 出错时返回 `None` .and_then(|x| bt.get(&x)) // 如果到目前为止我们有 `None`,则替换一条错误消息 .or(Some(&"error!")) .copied() // 不会 panic 因为我们无条件使用了上面的 `Some` .unwrap() }) .collect::<Vec<_>>(); assert_eq!(res, ["error!", "error!", "foo", "error!", "bar"]);Run
迭代结束 Option
可以对 Option 进行迭代。如果您需要一个条件为空的迭代器,这会很有帮助。迭代器将产生单个值 (当 Option 为 Some 时),或不产生任何值 (当 Option 为 None 时)。
例如,如果 Option 是 Some(v),则 into_iter 的作用类似于 once(v); 如果 Option 是 None,则它的作用类似于 empty()。
Option<T> 上的迭代器分为三种类型:
Option 上的迭代器在链接迭代器时很有用,例如,有条件地插入项。
(并不总是需要显式调用迭代器构造函数: 许多接受其他迭代器的 Iterator 方法也将接受实现 IntoIterator 的可迭代类型,其中包括 Option。)
let yep = Some(42); let nope = None; // chain() 已经调用 into_iter(),所以我们不必这样做 let nums: Vec<i32> = (0..4).chain(yep).chain(4..8).collect(); assert_eq!(nums, [0, 1, 2, 3, 42, 4, 5, 6, 7]); let nums: Vec<i32> = (0..4).chain(nope).chain(4..8).collect(); assert_eq!(nums, [0, 1, 2, 3, 4, 5, 6, 7]);Run
以这种方式链接迭代器的一个原因是,返回 impl Iterator 的函数必须使所有可能的返回值都具有相同的具体类型。链接一个迭代的 Option 可以帮助解决这个问题。
fn make_iter(do_insert: bool) -> impl Iterator<Item = i32> { // 显式返回来说明返回类型匹配 match do_insert { true => return (0..4).chain(Some(42)).chain(4..8), false => return (0..4).chain(None).chain(4..8), } } println!("{:?}", make_iter(true).collect::<Vec<_>>()); println!("{:?}", make_iter(false).collect::<Vec<_>>());Run
如果我们尝试做同样的事情,但是使用 once() 和 empty(),我们就不能再返回 impl Iterator,因为返回值的具体类型不同。
// 这不会编译,因为函数的所有可能返回必须具有相同的具体类型。 // fn make_iter(do_insert: bool) -> impl Iterator<Item = i32> { // 显式返回以说明返回类型不匹配 match do_insert { true => return (0..4).chain(once(42)).chain(4..8), false => return (0..4).chain(empty()).chain(4..8), } }Run
收集到 Option
Option 实现 FromIterator trait,它允许将 Option 值上的迭代器收集到原始 Option 值的每个包含值的集合的 Option 中,或者如果任何元素是 None,则为 None。
let v = vec![Some(2), Some(4), None, Some(8)]; let res: Option<Vec<_>> = v.into_iter().collect(); assert_eq!(res, None); let v = vec![Some(2), Some(4), Some(8)]; let res: Option<Vec<_>> = v.into_iter().collect(); assert_eq!(res, Some(vec![2, 4, 8]));Run
Option 还实现了 Product 和 Sum traits,允许对 Option 值的迭代器提供 product 和 sum 方法。
let v = vec![None, Some(1), Some(2), Some(3)]; let res: Option<i32> = v.into_iter().sum(); assert_eq!(res, None); let v = vec![Some(1), Some(2), Some(21)]; let res: Option<i32> = v.into_iter().product(); assert_eq!(res, Some(42));Run
就地修改 Option
这些方法返回对包含的值的可变引用
Option<T>:
insert插入一个值,丢弃任何旧内容get_or_insert获取当前值,如果是None,则插入提供的默认值get_or_insert_default获取当前值,如果是,则插入类型为T(必须实现Default) 的默认值Noneget_or_insert_with获取当前值,如果它是None,则插入由提供的函数计算的默认值
这些方法转移包含的值的所有权
Option:
take获取Option的包含值的所有权(如果有),将Option替换为Nonereplace获取Option的包含值的所有权,如果有的话,将Option替换为包含所提供值的Some
Examples
Option 上的基本模式匹配:
let msg = Some("howdy"); // 对包含的字符串加上引号 if let Some(m) = &msg { println!("{}", *m); } // 删除包含的字符串,销毁 Option let unwrapped_msg = msg.unwrap_or("default message");Run
循环前将结果初始化为 None:
enum Kingdom { Plant(u32, &'static str), Animal(u32, &'static str) } // 要搜索的数据列表。 let all_the_big_things = [ Kingdom::Plant(250, "redwood"), Kingdom::Plant(230, "noble fir"), Kingdom::Plant(229, "sugar pine"), Kingdom::Animal(25, "blue whale"), Kingdom::Animal(19, "fin whale"), Kingdom::Animal(15, "north pacific right whale"), ]; // 我们将搜索最大的动物的名称,但首先要获取 `None`。 // let mut name_of_biggest_animal = None; let mut size_of_biggest_animal = 0; for big_thing in &all_the_big_things { match *big_thing { Kingdom::Animal(size, name) if size > size_of_biggest_animal => { // 现在我们找到了一些大动物的名字 size_of_biggest_animal = size; name_of_biggest_animal = Some(name); } Kingdom::Animal(..) | Kingdom::Plant(..) => () } } match name_of_biggest_animal { Some(name) => println!("the biggest animal is {}", name), None => println!("there are no animals :("), }Run
Structs
| IntoIter | |
| Iter | |
| IterMut |
Enums
| Option |
|