Module std::option1.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 相同的大小:

这称为 “空指针优化” 或 NPO。

对于上述情况,可以进一步保证,可以从 TOption<T> 的所有有效值以及从 Some::<T>(_)T 的所有有效值 mem::transmute (但是将 None::<T> 转换为 T 是未定义的行为)。

方法概述

除了使用模式匹配,Option 还提供了多种不同的方法。

查询变量

如果 Option 分别为 SomeNone,则 is_someis_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_refPin<&Option<T>> 转换为 Option<Pin<&T>>
  • as_pin_mutPin<&mut Option<T>> 转换为 Option<Pin<&mut T>>

提取包含的值

这些方法提取 Option<T> 中包含的值,当它是 Some 成员时。如果 OptionNone:

转换包含的值

这些方法将 Option 转换为 Result:

这些方法改变了 Some 成员:

这些方法将 Option<T> 转换为可能不同类型 U 的值:

  • map_or 将提供的函数应用于 Some 的包含值,如果 Option 是,则返回提供的默认值 None
  • map_or_else 将提供的函数应用于 Some 的包含值,或者如果 OptionNone,则返回评估提供的回退函数的结果

这些方法结合了两个 Option 值的 Some 成员:

布尔运算符

这些方法将 Option 视为布尔值,其中 Some 的作用类似于 true,而 None 的作用类似于 false。这些方法有两类: 一类以 Option 作为输入,一类以函数作为输入 (延迟评估)。

andorxor 方法将另一个 Option 作为输入,并生成一个 Option 作为输出。只有 and 方法可以生成具有与 Option<T> 不同的内部类型 UOption<U> 值。

methodselfinputoutput
andNone(ignored)None
andSome(x)NoneNone
andSome(x)Some(y)Some(y)
orNoneNoneNone
orNoneSome(y)Some(y)
orSome(x)(ignored)Some(x)
xorNoneNoneNone
xorNoneSome(y)Some(y)
xorSome(x)NoneSome(x)
xorSome(x)Some(y)None

and_thenor_else 方法将函数作为输入,并且仅在需要产生新值时才评估函数。只有 and_then 方法可以生成具有与 Option<T> 不同的内部类型 UOption<U> 值。

methodselffunction inputfunction resultoutput
and_thenNone(not provided)(not evaluated)None
and_thenSome(x)xNoneNone
and_thenSome(x)xSome(y)Some(y)
or_elseNone(not provided)NoneNone
or_elseNone(not provided)Some(y)Some(y)
or_elseSome(x)(not provided)(not evaluated)Some(x)

这是在方法调用管道中使用 and_thenor 等方法的示例。管道的早期阶段通过不变的失败值 (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 进行迭代。如果您需要一个条件为空的迭代器,这会很有帮助。迭代器将产生单个值 (当 OptionSome 时),或不产生任何值 (当 OptionNone 时)。 例如,如果 OptionSome(v),则 into_iter 的作用类似于 once(v); 如果 OptionNone,则它的作用类似于 empty()

Option<T> 上的迭代器分为三种类型:

  • into_iter 消耗 Option 并产生包含的值
  • iter 对包含的值产生类型为 &T 的不支持引用
  • iter_mut 产生一个 &mut 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 还实现了 ProductSum traits,允许对 Option 值的迭代器提供 productsum 方法。

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>:

这些方法转移包含的值的所有权 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

Structs

IntoIter

OptionSome 成员中的值的迭代器。

Iter

OptionSome 成员的引用上的迭代器。

IterMut

OptionSome 成员的可变引用上的迭代器。

Enums

Option

Option 类型。有关更多信息,请参见 模块级文档