目录
在 Rust 中:
.await .map_err(...)
通常表示:
- 使用
.await等待异步操作完成; - 异步操作返回一个
Result<T, E>; - 使用
.map_err()把原来的错误E转换成另一种错误类型。
基本写法
let result = async_operation()
.await
.map_err(|err| {
// 将原错误转换成新错误
MyError::RequestFailed(err.to_string())
})?;
等价于:
let result = async_operation().await;
let result = result.map_err(|err| {
MyError::RequestFailed(err.to_string())
})?;
.await 返回什么
例如:
async fn query_user() -> Result<String, std::io::Error> {
Ok("Albert".to_string())
}
调用:
let user = query_user().await;
此时 user 的类型不是 String,而是:
Result<String, std::io::Error>
所以可以继续调用:
let user = query_user()
.await
.map_err(|err| err.to_string())?;
这里把:
std::io::Error
转换成了:
String
map_err() 的作用
假设原始结果为:
Result<T, E>
调用:
result.map_err(|error| new_error)
会得到:
Result<T, NewError>
它只转换 Err,不会修改 Ok。
例如:
let result: Result<i32, &str> = Err("数字解析失败");
let new_result: Result<i32, String> =
result.map_err(|err| format!("业务错误:{}", err));
结果是:
Err("业务错误:数字解析失败")
如果原结果是:
Ok(100)
那么调用 map_err() 后仍然是:
Ok(100)
常见完整案例
自定义错误类型
use thiserror::Error;
#[derive(Debug, Error)]
enum AppError {
#[error("读取文件失败:{0}")]
FileRead(String),
}
async fn read_config() -> Result<String, std::io::Error> {
tokio::fs::read_to_string("config.toml").await
}
async fn load_config() -> Result<String, AppError> {
let content = read_config()
.await
.map_err(|err| AppError::FileRead(err.to_string()))?;
Ok(content)
}
执行过程是:
read_config()
返回 Future,然后:
.await
等待 Future 完成,得到:
Result<String, std::io::Error>
再通过:
.map_err(|err| AppError::FileRead(err.to_string()))
转换为:
Result<String, AppError>
最后:
?
表示:
Ok(content):取出content,继续执行;Err(error):立即返回AppError。
.map_err() 里面必须传闭包
错误写法:
request()
.await
.map_err();
因为 map_err() 不知道要把错误转换成什么。
正确写法:
request()
.await
.map_err(|err| err.to_string())?;
或者:
request()
.await
.map_err(AppError::Request)?;
枚举构造函数可以直接传给 map_err
例如:
#[derive(Debug)]
enum AppError {
Io(std::io::Error),
}
可以写成:
let content = tokio::fs::read_to_string("config.toml")
.await
.map_err(AppError::Io)?;
它等价于:
let content = tokio::fs::read_to_string("config.toml")
.await
.map_err(|err| AppError::Io(err))?;
map_err() 与 map() 的区别
result.map(...)
转换成功值 Ok:
let result: Result<i32, String> = Ok(10); let result = result.map(|value| value * 2); // Ok(20)
而:
result.map_err(...)
转换错误值 Err:
let result: Result<i32, &str> = Err("失败");
let result = result.map_err(|err| err.to_string());
// Err(String)
最常见的组合
let value = some_async_function()
.await
.map_err(|err| AppError::Internal(err.to_string()))?;
可以理解为:
等待异步函数执行完成;如果失败,就把原始错误转换为
AppError::Internal,然后通过?向上返回;如果成功,就取出成功值。