【问题标题】: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

【问题讨论】:

    标签: error-handling rust idioms


    【解决方案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。我的问题是:这个附加层是正确的方法,还是我应该使用结果的结果?...
    猜你喜欢
    • 2010-09-27
    • 1970-01-01
    • 2013-09-13
    • 2015-09-20
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 2016-10-18
    相关资源
    最近更新 更多