【发布时间】:2021-02-23 18:43:35
【问题描述】:
给出以下两种错误类型和函数来说明它们的用法(Rust Playground link):
#[derive(std::fmt::Debug)]
struct MyError;
#[derive(std::fmt::Debug)]
struct OtherError;
impl std::error::Error for MyError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "MyError")
}
}
impl std::fmt::Display for OtherError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "OtherError")
}
}
impl std::error::Error for OtherError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl From<OtherError> for MyError {
fn from(_: OtherError) -> Self {
MyError {}
}
}
fn my_error() -> Result<(), MyError> { Ok(()) }
fn other_error() -> Result<(), OtherError> { Ok(()) }
如果我在一个返回 Result 且 MyError 作为其 Error 类型的函数中,我可以调用返回 MyError 和 OtherError 的两个函数,因为它们之间存在一个 From 转换。
但是,我不能简单地为“其他”类型返回 Result,我需要使用 ? 后跟 Ok(())。这在我看来不一致。
例如,这很好用:
fn main() -> Result<(), MyError> {
my_error()
}
这也可以:
fn main() -> Result<(), MyError> {
my_error()?;
other_error()?;
my_error()
}
但这失败了:
fn main() -> Result<(), MyError> {
my_error()?;
other_error()
}
错误:
error[E0308]: mismatched types
--> src/main.rs:43:5
|
41 | fn main() -> Result<(), MyError> {
| ------------------- expected `std::result::Result<(), MyError>` because of return type
42 | my_error()?;
43 | other_error()
| ^^^^^^^^^^^^^ expected struct `MyError`, found struct `OtherError`
|
= note: expected enum `std::result::Result<_, MyError>`
found enum `std::result::Result<_, OtherError>`
这是为什么呢?
这使我的一些代码更加冗长,因为我发现我需要这样做才能让它工作:
fn main() -> Result<(), MyError> {
my_error()?;
other_error()?;
Ok(())
}
这是唯一的解决方案吗?我更有兴趣了解它以这种方式工作的原因,但如果我在做一些愚蠢的事情,请随时指出可以做得更好的地方。
【问题讨论】:
-
我知道这不是您要问的。但简而言之,这是因为
?是糖,其中包括使用From转换错误。如果只是单独做returning,那会有点可怕。 -
等效的匹配表达式似乎没有调用
into()或其他调用From的方法?它是否说它在某处这样做? -
如果有的话,这个问题让我比@vallentin 之前更加困惑。根据那个答案,
?不应该像我的示例那样工作。 -
Rust Book 似乎没有提到任何关于
From:from(err)的内容,而您链接到的其他答案也没有。最好有一个“正确”的答案来显示try!的实际作用(该答案中未显示)。只有该答案中提到的 RFC 似乎显示了e.into()的用法,但这是一个设计提案(看起来与当前的 Rust 不同)。 IMO 的情况非常不理想。 -
@vallentin 当然可以,但是在您开始同意我的观点之前,答案必须是多么间接,这并没有解决我的问题(并且 RFC 与当前的 Rust 实现不同)? try! 文档提到 try!发生错误时使用 From 执行转换,并且
?运算符“替换”它...
标签: error-handling rust