2.4 Try 类型转换
04-Try 类型转换 — Comprehensive Rust
译文 · 基于 Comprehensive Rust
原文链接: https://google.github.io/comprehensive-rust/error-handling/try-conversions.html
2.4 Try 类型转换
? 的实际展开比前面说的更复杂一点:
1
2
3
| // Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
expression?
|
等价于
1
2
3
4
5
6
| // Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
match expression {
Ok(value) => value,
Err(err) => return Err(From::from(err)),
}
|
这里的 From::from 表示尝试把错误类型转换成函数返回类型中的错误类型。这使得把底层错误封装进更高层错误变得很容易。
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| // Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use std::io::Read;
use std::{fmt, fs, io};
#[derive(Debug)]
enum ReadUsernameError {
IoError(io::Error),
EmptyUsername(String),
}
impl Error for ReadUsernameError {}
impl fmt::Display for ReadUsernameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::IoError(e) => write!(f, "I/O error: {e}"),
Self::EmptyUsername(path) => write!(f, "Found no username in {path}"),
}
}
}
impl From<io::Error> for ReadUsernameError {
fn from(err: io::Error) -> Self {
Self::IoError(err)
}
}
fn read_username(path: &str) -> Result<String, ReadUsernameError> {
let mut username = String::with_capacity(100);
fs::File::open(path)?.read_to_string(&mut username)?;
if username.is_empty() {
return Err(ReadUsernameError::EmptyUsername(String::from(path)));
}
Ok(username)
}
fn main() {
//std::fs::write("config.dat", "").unwrap();
let username = read_username("config.dat");
println!("username or error: {username:?}");
}
|
讲师备注? 运算符必须返回与函数返回类型兼容的值。对 Result 而言,意味着错误类型必须兼容:返回 Result<T, ErrorOuter> 的函数只能对 Result<U, ErrorInner> 使用 ?,前提是 ErrorOuter 与 ErrorInner 是同一类型,或 ErrorOuter 实现了 From<ErrorInner>。
From 实现的常见替代方案是 Result::map_err,尤其是转换只发生在一处时。
对 Option 没有兼容性要求:返回 Option<T> 的函数可以对任意 T、U 的 Option<U> 使用 ?。
返回 Result 的函数不能对 Option 使用 ?,反之亦然。不过,Option::ok_or 可以把 Option 转成 Result,而 Result::ok 可以把 Result 转成 Option。