我在Rust中很难干净地处理错误。假设我有一个用Box<dyn Error>
传播多个错误类型的函数。要打开并处理错误,我将执行以下操作:
fn main() {
let json =
get_json_response(format!("{}{}", BASE_URL, LOGIN_URL).as_str()).unwrap_or_else(|e| {
eprintln!("Error: failed to get: {}", e);
std::process::exit(1);
});
}
fn get_json_response(url: &str) -> Result<Value, Box<dyn Error>> {
let resp = ureq::get(url)
.set("Authorization", format!("Bearer {}", API_TOKEN).as_str())
.call()?
.into_json()?;
Ok(resp)
}
这个很好用。但是,如果我对get_json_response()
进行多次调用,那么反复包含相同的闭包会变得很混乱。
我的解决方案是将其改为:
use serde_json::Value;
use std::error::Error;
use ureq;
fn main() {
let json =
get_json_response(format!("{}{}", BASE_URL, LOGIN_URL).as_str()).unwrap_or_else(fail);
}
fn fail(err: Box<dyn Error>) -> ! {
eprintln!("Error: failed to get: {}", err);
std::process::exit(1);
}
这不起作用,因为unwrap_or_else()
期望返回一个Value
,而不是什么!
。我可以欺骗并将fail()
的返回值更改为-> Value
,并在exit(1)
之后添加Value::Null
。它工作,但感觉错误(并抱怨)。
我也可以做unwrap_or_else(|e| fail(e))
,这并不可怕。
有没有一个习惯的方法来处理这个问题?
2条答案
按热度按时间vh0rcniy1#
正如@kmdreko所指出的,代码编译失败是因为
!
可以强制到任何T
,fn() -> !
不能强制到fn() -> T
。要解决上述问题,您可以声明
fail()
以返回Value
,实际上返回std::process::exit(1)
的“值”。省略分号可以将!
强制转换为Value
,你不必用Value::Null
作弊:Playground
bvhaajcl2#
我不确定这是否符合Rust的习惯,但你可以把所有的东西放在一个闭包中,然后处理
Result
: