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 有 optional 指针,就像可选的拥有所有权的 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问号运算符,?
与 Result
类型类似,在编写调用许多返回 Option
类型的函数的代码时,处理 Some
/None
可能会很乏味。问号运算符 ?
隐藏了一些在调用栈上传播值的样板。
它将替换为:
fn add_last_numbers(stack: &mut Vec<i32>) -> Option<i32> {
let a = stack.pop();
let b = stack.pop();
match (a, b) {
(Some(x), Some(y)) => Some(x + y),
_ => None,
}
}
Run有了这个:
fn add_last_numbers(stack: &mut Vec<i32>) -> Option<i32> {
Some(stack.pop()? + stack.pop()?)
}
Run好多了!
以 ?
结尾的表达式将导致 Some
的展开值,除非结果为 None
,在这种情况下,None
会从封闭的函数中提前返回。
?
可以用在返回 Option
的函数中,因为它提供了 None
的提前返回。
Representation
Rust 保证优化以下 T
类型,以使 Option<T>
具有与 T
相同的大小:
Box<U>
&U
&mut U
fn
,extern "C" fn
1num::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>>
提取包含的值
当它是 Some
变体时,这些方法提取 Option<T>
中包含的值。如果 Option
为 None
:
expect
panics 带有提供的自定义消息unwrap
panics 带有泛型信息unwrap_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
transposes anOption
of aResult
into aResult
of anOption
这些方法转换了 Some
变体:
filter
calls the provided predicate function on the contained valuet
if theOption
isSome(t)
, and returnsSome(t)
if the function returnstrue
; otherwise, returnsNone
flatten
从一个对象中删除一层嵌套Option<Option<T>>
map
通过将提供的函数应用于Some
的包含值并保持None
值不变,将Option<T>
转换为Option<U>
这些方法将 Option<T>
转换为可能不同类型 U
的值:
map_or
将提供的函数应用于Some
的包含值,或者如果Option
是返回提供的默认值None
map_or_else
applies the provided function to the contained value ofSome
, or returns the result of evaluating the provided fallback function if theOption
isNone
zip
returnsSome((s, o))
ifself
isSome(s)
and the providedOption
value isSome(o)
; otherwise, returnsNone
zip_with
calls the provided functionf
and returnsSome(f(s, o))
ifself
isSome(s)
and the providedOption
value isSome(o)
; otherwise, returnsNone
布尔运算符
这些方法将 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 = [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比较运算符
如果 T
实现 PartialOrd
,那么 Option<T>
将派生其 PartialOrd
实现。使用此顺序,None
的比较比任何 Some
都小,两个 Some
的比较方式与其在 T
中包含的值相同。
如果 T
也实现了 Ord
,那么 Option<T>
也是如此。
assert!(None < Some(0));
assert!(Some(0) < Some(1));
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 = [Some(2), Some(4), None, Some(8)];
let res: Option<Vec<_>> = v.into_iter().collect();
assert_eq!(res, None);
let v = [Some(2), Some(4), Some(8)];
let res: Option<Vec<_>> = v.into_iter().collect();
assert_eq!(res, Some(vec![2, 4, 8]));
RunOption
还实现了 Product
和 Sum
traits,允许对 Option
值的迭代器提供 product
和 sum
方法。
let v = [None, Some(1), Some(2), Some(3)];
let res: Option<i32> = v.into_iter().sum();
assert_eq!(res, None);
let v = [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
gets the current value, inserting a provided default value if it isNone
get_or_insert_default
获取当前值,如果是,则插入类型T
(必须实现Default
) 的默认值None
get_or_insert_with
gets the current value, inserting a default computed by the provided function if it isNone
这些方法转移包含的值的所有权
Option
:
take
takes ownership of the contained value of anOption
, if any, replacing theOption
withNone
replace
获得Option
包含的值的所有权 (如果有),用包含提供的值的Some
替换Option
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这对于任何其他 ABI 仍然适用:
extern "abi" fn
(例如,extern "system" fn
) ↩
Structs
Enums
Option
类型。有关更多信息,请参见 模块级文档。