合并两种错误类型最惯用的方法是啥?

Posted

技术标签:

【中文标题】合并两种错误类型最惯用的方法是啥?【英文标题】:What is the most idiomatic way to merge two error types?合并两种错误类型最惯用的方法是什么? 【发布时间】:2019-02-25 14:00:47 【问题描述】:

我有一个类型 Foo,其方法可能会“引发”关联类型 Foo::Err 的错误。

pub trait Foo 
    type Err;
    
    fn foo(&mut self) -> Result<(), Self::Err>;

我有另一个特征Bar,其方法旨在处理FooBar 可能会发出自己的错误(由关联类型 Bar::Err 指定),但它也可能遇到由正在处理的 Foo 生成的错误。

我可以看到两种方法来做到这一点,但我不知道哪种方法最适合 Rust。

第一个在结果中嵌入结果:

pub trait Bar1 
    type Err;
    
    fn bar<F: Foo>(&mut self, foo: F) -> Result<Result<F, F::Err>, Self::Err>;

第二个将两种错误类型合并到一个专用的枚举中:

pub trait Bar2 
    type Err;
    
    fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Choice<F::Err, Self::Err>>;

第二个在语义上看起来更清晰,但为处理额外的枚举带来了一些障碍。

playground

【问题讨论】:

【参考方案1】:

您应该使用 trait 对象 Error,然后返回遇到的第一个错误:

pub trait Bar 
    fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Box<dyn Error>>;

或者像这样实现你的特质:

impl Bar for MyType 
    type Err = Box<dyn Error>;

    fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Self::Err>;

如果你真的想有两个错误(但这很奇怪,因为一个错误就足以使过程不正常),你可以使用像 failure 这样的板条箱来创建一个“错误跟踪”。

作为一般建议,您不应忘记使用 std 中的特征来为您的代码添加更多语义。

【讨论】:

@trentcl 哦,你是对的,Err 之后就没用了:P 谢谢你的评论。 关于错误特征的好点,这确实是我必须使用的东西。实际上,这打开了返回 Box 的第三个选项。但是,该选项对调用者似乎不是很有用。他们无法将其与不同的错误变体进行匹配以决定下一步该做什么...... 使用类似失败的板条箱——注意失败已被弃用。请参阅How do you define custom Error types in Rust? 以获取选定替代方案的列表。【参考方案2】:

通常您不会执行“合并”,而是使用嵌套错误,就像这样。

enum IntError 
    Overflow,
    Underflow


enum StrError 
    TooLong,
    TooShort,


enum GenericError 
    Int(IntError),
    Str(StrError),


impl From<IntError> for GenericError 
    fn from(e: IntError) -> Self 
        GenericError::Int(e)
    


impl From<StrError> for GenericError 
    fn from(e: StrError) -> Self 
        GenericError::Str(e)
    

【讨论】:

对不起,如果我的例子不清楚;当我写到“将两个错误 types 合并到一个专用枚举中”时,我想到的就是你的GenericError。我的问题是:这个附加层是正确的方法,还是我应该使用结果的结果?...

以上是关于合并两种错误类型最惯用的方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在颤振飞镖中合并2个对象列表的最简单方法是啥?

在 Vim 中,将文件中的所有行合并为一行的最简单方法是啥?

在python中合并两个列表的最快方法是啥?

如果成功,从没有结果的函数返回错误的惯用方法是啥?

检查 Python 变量类型的最佳(惯用)方法是啥? [复制]

处理在多个 for 循环中声明的变量的最惯用方法是啥? [关闭]