Module std::result 1.0.0[−][src]
Expand description
Result
类型的错误处理。
Result<T, E>
是用于返回和传播错误的类型。
它是一个枚举,成员 Ok(T)
表示成功并包含一个值,而 Err(E)
表示错误并包含错误值。
enum Result<T, E> { Ok(T), Err(E), }Run
只要预期到错误并且可以恢复,函数就返回 Result
。在 std
crate 中,Result
最主要用于 I/O。
返回 Result
的简单函数可以像这样定义和使用:
#[derive(Debug)] enum Version { Version1, Version2 } fn parse_version(header: &[u8]) -> Result<Version, &'static str> { match header.get(0) { None => Err("invalid header length"), Some(&1) => Ok(Version::Version1), Some(&2) => Ok(Version::Version2), Some(_) => Err("invalid version"), } } let version = parse_version(&[1, 2, 3, 4]); match version { Ok(v) => println!("working with version: {:?}", v), Err(e) => println!("error parsing header: {:?}", e), }Run
在简单情况下,在 Result
上进行模式匹配非常简单明了,但是 Result
附带了一些方便的方法,使使用它更加简洁。
let good_result: Result<i32, i32> = Ok(10); let bad_result: Result<i32, i32> = Err(10); // `is_ok` 和 `is_err` 方法按照他们说的做。 assert!(good_result.is_ok() && !good_result.is_err()); assert!(bad_result.is_err() && !bad_result.is_ok()); // `map` 消耗 `Result` 并产生另一个。 let good_result: Result<i32, i32> = good_result.map(|i| i + 1); let bad_result: Result<i32, i32> = bad_result.map(|i| i - 1); // 使用 `and_then` 继续计算。 let good_result: Result<bool, i32> = good_result.and_then(|i| Ok(i == 11)); // 使用 `or_else` 处理该错误。 let bad_result: Result<i32, i32> = bad_result.or_else(|i| Ok(i + 20)); // 消费结果并用 `unwrap` 返回内容。 let final_awesome_result = good_result.unwrap();Run
必须使用结果
使用返回值指示错误的一个常见问题是,很容易忽略返回值,从而无法处理错误。
Result
带有 #[must_use]
属性的注解,它将导致编译器在忽略 Result 值时发出警告。
这使得 Result
对于可能遇到错误但不会返回有用值的函数特别有用。
考虑 Write
trait 为 I/O 类型定义的 write_all
方法:
use std::io; trait Write { fn write_all(&mut self, bytes: &[u8]) -> Result<(), io::Error>; }Run
Note: Write
的实际定义使用 io::Result
,它只是 Result
的同义词。
io::Error
>
.
该方法不会产生值,但是写入可能会失败。处理错误情况至关重要,并且 不要 编写类似以下内容的代码:
use std::fs::File; use std::io::prelude::*; let mut file = File::create("valuable_data.txt").unwrap(); // 如果 `write_all` 错误,那么我们将永远不会知道,因为返回值将被忽略。 // file.write_all(b"important message");Run
如果您确实将其写在 Rust 中,则编译器将向您发出警告 (默认情况下,由 unused_must_use
lint 控制)。
相反,如果您不想处理该错误,则可以断言 expect
成功。
如果写入失败,这将为 panic,提供了一条边际有用的消息,指出原因:
use std::fs::File; use std::io::prelude::*; let mut file = File::create("valuable_data.txt").unwrap(); file.write_all(b"important message").expect("failed to write message");Run
您可能还简单地宣称成功:
assert!(file.write_all(b"important message").is_ok());Run
或者使用 ?
在调用栈中传播错误:
fn write_message() -> io::Result<()> { let mut file = File::create("valuable_data.txt")?; file.write_all(b"important message")?; Ok(()) }Run
问号运算符, ?
在编写调用许多返回 Result
类型的函数的代码时,错误处理可能很乏味。
问号运算符 ?
在调用栈中隐藏了一些传播错误的样板。
它将替换为:
use std::fs::File; use std::io::prelude::*; use std::io; struct Info { name: String, age: i32, rating: i32, } fn write_info(info: &Info) -> io::Result<()> { // 尽早返回错误 let mut file = match File::create("my_best_friends.txt") { Err(e) => return Err(e), Ok(f) => f, }; if let Err(e) = file.write_all(format!("name: {}\n", info.name).as_bytes()) { return Err(e) } if let Err(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) { return Err(e) } if let Err(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) { return Err(e) } Ok(()) }Run
有了这个:
use std::fs::File; use std::io::prelude::*; use std::io; struct Info { name: String, age: i32, rating: i32, } fn write_info(info: &Info) -> io::Result<()> { let mut file = File::create("my_best_friends.txt")?; // 尽早返回错误 file.write_all(format!("name: {}\n", info.name).as_bytes())?; file.write_all(format!("age: {}\n", info.age).as_bytes())?; file.write_all(format!("rating: {}\n", info.rating).as_bytes())?; Ok(()) }Run
好多了!
用 ?
结束表达式将得到未包装的成功 (Ok
) 值,除非结果为 Err
,在这种情况下,Err
会从封闭的函数中提前返回。
?
只能在返回 Result
的函数中使用,因为它提供了 Err
的较早返回。
方法概述
除了使用模式匹配,Result
还提供了多种不同的方法。
查询变量
如果 Result
分别为 Ok
或 Err
,则 is_ok
和 is_err
方法返回 true
。
用于处理引用的适配器
as_ref
从&Result<T, E>
转换为Result<&T, &E>
as_mut
从&mut Result<T, E>
转换为Result<&mut T, &mut E>
as_deref
从&Result<T, E>
转换为Result<&T::Target, &E>
as_deref_mut
从&mut Result<T, E>
转换为Result<&mut T::Target, &mut E>
提取包含的值
当它是 Ok
成员时,这些方法提取 Result<T, E>
中包含的值。如果 Result
是 Err
:
expect
一个提供自定义消息的 panicsunwrap
带有通用消息的 panicsunwrap_or
返回提供的默认值unwrap_or_default
返回类型T
的默认值 (必须实现Default
trait)unwrap_or_else
返回对提供的函数求值的结果
panicking 方法 expect
和 unwrap
需要 E
来实现 Debug
trait。
当它是 Err
成员时,这些方法提取 Result<T, E>
中包含的值。他们需要 T
来实现 Debug
trait。如果 Result
是 Ok
:
expect_err
一个提供自定义消息的 panicsunwrap_err
带有通用消息的 panics
转换包含的值
err
将Result<T, E>
转换为Option<E>
,将Err(e)
映射到Some(e)
,将Ok(v)
映射到None
ok
将Result<T, E>
转换为Option<T>
,将Ok(v)
映射到Some(v)
,将Err(e)
映射到None
transpose
将Option
的Result
转换为Result
的Option
此方法转换 Ok
成员的包含值:
map
通过将提供的函数应用于Ok
的包含值并保持Err
值不变,将Result<T, E>
转换为Result<U, E>
此方法转换 Err
成员的包含值:
map_err
通过将提供的函数应用于Err
的包含值并保持Ok
值不变,将Result<T, E>
转换为Result<T, F>
这些方法将 Result<T, E>
转换为可能不同类型 U
的值:
map_or
将提供的函数应用于Ok
的包含值,如果Result
是,则返回提供的默认值Err
map_or_else
将提供的函数应用于Ok
的包含值,或将提供的回退函数应用于Err
的包含值
布尔运算符
这些方法将 Result
视为布尔值,其中 Ok
的作用类似于 true
,而 Err
的作用类似于 false
。这些方法有两类: 一类以 Result
作为输入,一类以函数作为输入 (延迟评估)。
and
和 or
方法将另一个 Result
作为输入,并生成一个 Result
作为输出。and
方法可以生成具有与 Result<T, E>
不同的内部类型 U
的 Result<U, E>
值。
or
方法可以生成具有与 Result<T, E>
不同的错误类型 F
的 Result<T, F>
值。
method | self | input | output |
---|---|---|---|
and | Err(e) | (ignored) | Err(e) |
and | Ok(x) | Err(d) | Err(d) |
and | Ok(x) | Ok(y) | Ok(y) |
or | Err(e) | Err(d) | Err(d) |
or | Err(e) | Ok(y) | Ok(y) |
or | Ok(x) | (ignored) | Ok(x) |
and_then
和 or_else
方法将函数作为输入,并且仅在需要产生新值时才评估函数。and_then
方法可以生成具有与 Result<T, E>
不同的内部类型 U
的 Result<U, E>
值。
or_else
方法可以生成具有与 Result<T, E>
不同的错误类型 F
的 Result<T, F>
值。
method | self | function input | function result | output |
---|---|---|---|---|
and_then | Err(e) | (not provided) | (not evaluated) | Err(e) |
and_then | Ok(x) | x | Err(d) | Err(d) |
and_then | Ok(x) | x | Ok(y) | Ok(y) |
or_else | Err(e) | e | Err(d) | Err(d) |
or_else | Err(e) | e | Ok(y) | Ok(y) |
or_else | Ok(x) | (not provided) | (not evaluated) | Ok(x) |
迭代 Result
可以对 Result
进行迭代。如果您需要一个条件为空的迭代器,这会很有帮助。迭代器将产生单个值 (当 Result
为 Ok
时),或不产生任何值 (当 Result
为 Err
时)。
例如,如果 Result
是 Ok(v)
,则 into_iter
的作用类似于 once(v)
; 如果 Result
是 Err
,则它的作用类似于 empty()
。
Result<T, E>
上的迭代器分为三种类型:
有关这如何有用的示例,请参见 迭代 Option
。
您可能希望使用迭代器链来执行可能失败的操作的多个实例,但希望在继续处理成功结果的同时忽略失败。
在本例中,我们利用 Result
的可迭代特性,使用 flatten
仅选择 Ok
值。
let mut results = vec![]; let mut errs = vec![]; let nums: Vec<_> = vec!["17", "not a number", "99", "-27", "768"] .into_iter() .map(u8::from_str) // 保存原始 `Result` 值的克隆以进行检查 .inspect(|x| results.push(x.clone())) // 挑战: 解释这如何仅捕获 `Err` 值 .inspect(|x| errs.extend(x.clone().err())) .flatten() .collect(); assert_eq!(errs.len(), 3); assert_eq!(nums, [17, 99]); println!("results {:?}", results); println!("errs {:?}", errs); println!("nums {:?}", nums);Run
收集到 Result
Result
实现 FromIterator
trait,它允许将 Result
值上的迭代器收集到原始 Result
值的每个包含值的集合的 Result
中,或者如果任何元素是 Err
,则为 Err
。
let v = vec![Ok(2), Ok(4), Err("err!"), Ok(8)]; let res: Result<Vec<_>, &str> = v.into_iter().collect(); assert_eq!(res, Err("err!")); let v = vec![Ok(2), Ok(4), Ok(8)]; let res: Result<Vec<_>, &str> = v.into_iter().collect(); assert_eq!(res, Ok(vec![2, 4, 8]));Run
Result
还实现了 Product
和 Sum
traits,允许对 Result
值的迭代器提供 product
和 sum
方法。
let v = vec![Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")]; let res: Result<i32, &str> = v.into_iter().sum(); assert_eq!(res, Err("error!")); let v: Vec<Result<i32, &str>> = vec![Ok(1), Ok(2), Ok(21)]; let res: Result<i32, &str> = v.into_iter().product(); assert_eq!(res, Ok(42));Run
Structs
IntoIter | |
Iter | |
IterMut |
Enums
Result |