我如何使用函数而不是闭包以惯用的方式解包 Rust 错误?
How do I idiomatically unwrap Rust errors with functions rather than closures?
我正在努力在 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
被 return 编辑,而不是什么都没有 !
。我可以作弊,把fail()
的return值改成-> Value
,在exit(1)
后面加上Value::Null
。它有效但感觉不对(并抱怨)。
我也可以 unwrap_or_else(|e| fail(e))
这并不可怕。
有没有惯用的方法来处理这个问题?
作为@kmdreko 的 ,您的代码无法编译,因为虽然 !
可以被强制转换为任何 T
,但 fn() -> !
不能被强制转换为 fn() -> T
.
要解决上述问题,您可以将 fail()
声明为 return Value
,实际上 return 是 std::process::exit(1)
的“值”。省略分号会将 !
强制为 Value
,并且您不必使用 Value::Null
:
作弊
fn main() {
let _json = get_json_response("...").unwrap_or_else(fail).as_str();
}
fn fail(err: Box<dyn Error>) -> Value {
eprintln!("Error: failed to get: {}", err);
std::process::exit(1)
}
我正在努力在 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
被 return 编辑,而不是什么都没有 !
。我可以作弊,把fail()
的return值改成-> Value
,在exit(1)
后面加上Value::Null
。它有效但感觉不对(并抱怨)。
我也可以 unwrap_or_else(|e| fail(e))
这并不可怕。
有没有惯用的方法来处理这个问题?
作为@kmdreko 的 !
可以被强制转换为任何 T
,但 fn() -> !
不能被强制转换为 fn() -> T
.
要解决上述问题,您可以将 fail()
声明为 return Value
,实际上 return 是 std::process::exit(1)
的“值”。省略分号会将 !
强制为 Value
,并且您不必使用 Value::Null
:
fn main() {
let _json = get_json_response("...").unwrap_or_else(fail).as_str();
}
fn fail(err: Box<dyn Error>) -> Value {
eprintln!("Error: failed to get: {}", err);
std::process::exit(1)
}