Module std::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 U
fn
,extern "C" fn
num::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
的默认值 (必须实现Default
trait)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)
; 否则,返回None
flatten
从一个嵌套中删除一层Option<Option<T>>
map
通过将提供的函数应用于Some
的包含值并保持None
值不变,将Option<T>
转换为Option<U>
这些方法将 Option<T>
转换为可能不同类型 U
的值:
map_or
将提供的函数应用于Some
的包含值,如果Option
是,则返回提供的默认值None
map_or_else
将提供的函数应用于Some
的包含值,或者如果Option
是None
,则返回评估提供的回退函数的结果
zip
如果self
为Some(s)
且提供的Option
值为Some(o)
,则返回Some((s, o))
; 否则,返回None
zip_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
) 的默认值None
get_or_insert_with
获取当前值,如果它是None
,则插入由提供的函数计算的默认值
这些方法转移包含的值的所有权
Option
:
take
获取Option
的包含值的所有权(如果有),将Option
替换为None
replace
获取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 |
|