Error handling 为什么Rust在使用';时会在错误类型之间进行隐式转换';但没有回报价值?

Error handling 为什么Rust在使用';时会在错误类型之间进行隐式转换';但没有回报价值?,error-handling,rust,Error Handling,Rust,给出以下两种错误类型和函数来说明它们的用法(): #[派生(std::fmt::Debug)] 结构MyError; #[派生(std::fmt::Debug)] 结构错误; impl std::error::MyError的错误{ fn源(&self)->选项{ 没有一个 } } 来自MyError的impl{ fn from(u:OtherError)->Self{ MyError{} } } fn my_error()->结果{Ok(())} fn other_error()->结果{Ok

给出以下两种错误类型和函数来说明它们的用法():

#[派生(std::fmt::Debug)]
结构MyError;
#[派生(std::fmt::Debug)]
结构错误;
impl std::error::MyError的错误{
fn源(&self)->选项{
没有一个
}
}
来自MyError的impl{
fn from(u:OtherError)->Self{
MyError{}
}
}
fn my_error()->结果{Ok(())}
fn other_error()->结果{Ok(())}
如果我在一个返回
Result
MyError
作为其
Error
类型的函数中,我可以调用返回
MyError
OtherError
的两个函数,因为它们之间有一个
From
转换

但是,对于“other”类型,我不能简单地返回
结果
,我需要使用
后跟
Ok(())
。我觉得这不一致

例如,这很好:

fn main()->结果{
我的错误()
}
这还包括:

fn main()->结果{
我的错误()?;
其他_错误()?;
我的错误()
}
但这失败了:

fn main()->结果{
我的错误()?;
其他_错误()
}
错误:

错误[E0308]:类型不匹配
-->src/main.rs:43:5
|
41 | fn main()->结果{
|--------------由于返回类型,应为'std::result::result'
42 |我的错误()?;
43 |其他错误()
|^^^^^^^^^^^^^^^应为结构“MyError”,找到结构“OtherError”`
|
=注意:预期枚举`std::result::result`
找到枚举'std::result::result'`
为什么呢

这使得我的一些代码更加冗长,因为我发现我需要这样做才能让它工作:

fn main()->结果{
我的错误()?;
其他_错误()?;
好(())
}

这是唯一的解决方案吗?我更感兴趣的是理解它以这种方式工作的原因,但是如果我正在做一些愚蠢的事情,请随意指出可以做得更好的地方。

操作符与宏等效,其简化版本如下:

macro_规则!试试看{
($expr:expr$(,)?)=>{
匹配$expr{
Ok(val)=>val,
错误(Err)=>{
返回Err(From::From(Err));
}
}
};
}
你可以在这本书的第页的部分找到这方面的参考资料

清单9-6中的
match
表达式与
运算符的作用有所不同:调用了
运算符的错误值通过标准库中trait
中定义的函数,该函数用于将错误从一种类型转换为另一种类型呃,
运算符调用函数时,接收到的错误类型将转换为当前函数的返回类型中定义的错误类型。当函数返回一种错误类型以表示函数可能失败的所有方式时,这非常有用,即使部分可能由于许多不同原因失败。只要每个错误类型实现定义如何将自身转换为返回的错误类型的函数,
运算符自动处理转换

(强调矿山)

您还可以在中找到这方面的参考资料,您可以在该部分中找到相关信息


因此,
操作符应该执行这样的隐式转换,其本质是子类型到超类型的强制。目前的RFC为此目的使用了该特性(它具有一个覆盖的
impl
转发源)。[…]

–-

另见:

中的页面还提到了隐式转换行为。它还提供了创建自定义错误类型的示例


因此,总结如下:

fn main() -> Result<(), MyError> {
    my_error()?;
    other_error()?;
    Ok(())
}
如果您的
MyError
是一个
enum
,它有一个
MyError::OtherError
变量,那么您甚至可以执行
.map\u err(MyError::OtherError)

这是因为,不仅构造一个
枚举
看起来像一个函数调用,.

我知道这并不是你要问的。但简而言之,这是因为
是糖,包括使用
转换错误。如果仅仅做
返回
ing就这样做了,那就有点可怕了匹配表达式似乎没有将
调用到()中
或任何调用
From
的东西?它说它在某个地方这样做了吗?如果有的话,这个问题让我比以前更困惑@vallentin。根据这个答案,
不应该像我的示例中那样工作。似乎没有提到任何关于
From:From(err)
而您链接到的另一个答案也没有。最好有一个“正确”的答案,显示
尝试!
实际上做了什么(没有显示在该答案中)。只有该答案中提到的RFC似乎显示了
e.into()
的用法,但这是一个设计方案(看起来与当前版本不同)。非常不满意的情况。@vallentin当然,但在你开始同意我之前,答案必须是多么间接?这并没有解决我的问题(而且RFC与当前的Rust实现不同)?文档中提到try!在出现错误时使用From执行转换,
运算符“替换”它…为了完整性起见,您可以使用
other_error().map_err(From::From)绕过额外的
Ok(())
,它基本上执行与match语句中相同的转换操作。但这并不是说不那么详细。@Johann150确实如此,但更清楚的是。如果编译器可以推断
fn main() -> Result<(), MyError> {
    match my_error() {
        Ok(_) => {}
        Err(err) => return Err(From::from(err));
    }
    match other_error() {
        Ok(_) => {}
        Err(err) => return Err(From::from(err));
    }
    Ok(())
}