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

Pie*_*ine 5 error-handling idioms rust

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

pub trait Foo {
    type Err;
    
    fn foo(&mut self) -> Result<(), Self::Err>;
}
Run Code Online (Sandbox Code Playgroud)

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

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

第一个将结果嵌入到结果中:

pub trait Bar1 {
    type Err;
    
    fn bar<F: Foo>(&mut self, foo: F) -> Result<Result<F, F::Err>, Self::Err>;
}
Run Code Online (Sandbox Code Playgroud)

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

pub trait Bar2 {
    type Err;
    
    fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Choice<F::Err, Self::Err>>;
}
Run Code Online (Sandbox Code Playgroud)

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

操场

hel*_*low 8

通常你不做“合并”,而是使用嵌套错误,就像这样。

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 抱歉,如果我的例子不清楚;当我写到“将两个错误*类型*合并到一个专用枚举中”时,我想到的正是像您的“GenericError”一样。我的问题是:这个附加层是正确的方法吗,还是我应该使用结果的结果?... (3认同)

Fre*_*ios 6

您应该使用特征对象Error,并返回遇到的第一个错误:

pub trait Bar {
    fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Box<dyn Error>>;
}
Run Code Online (Sandbox Code Playgroud)

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

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

    fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Self::Err>;
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • *使用像失败这样的箱子* - 请注意,失败已被弃用。有关选定替代方案的列表,请参阅[如何在 Rust 中定义自定义“Error”类型?](/sf/ask/2980905791/)。 (2认同)