generics - 无法创建简洁和通用的错误类型

标签 generics types error-handling rust

我很难尝试创建一个既通用又不会演变成一团糟的错误类型 impl s 和通用参数。

我有一个包含一些子系统通用参数的结构,每个子系统都有返回自定义错误类型的方法:

struct App<A: ..., B: ..., ...> {
    a: A,
    b: B,
    ...
}

impl<A: ..., B: ..., ...> App<A, B, ...> {
    fn do_something_cross_cutting(&self) -> Result<(), AppError> {
        a.run()?;
        b.run()?;

        Ok(())
    }
}

应该怎样AppError被明确定义?起初我尝试使用 quick_error!像这样:

quick_error! {
    #[derive(Debug)]
    enum AppError<A: ..., B: ..., ...> {
        AError(err: A::Error) {
            from()
            display(...)
        }

        BError(err: B::Error) {
            from()
            display(...)
        }

        ...
    }
}

但是quick_error!似乎不支持通用枚举。此外,由于 AppError现在是通用的 and 它看起来不可能在 impl 中定义类型别名 block ,每个可能失败的方法都会有一个非常广泛的返回类型(Result<_, AppError<A, B, ...>>)。

quick_error!可以避免,但又会以可读性和代码大小为代价,并且它不能解决第二个问题。

我想出了以下替代方案,但没有编译:

quick_error! {
    #[derive(Debug)]
    enum AppError {
        AError(err: Box<Error>) {
            display(...)
        }

        BError(err: Box<Error>) {
            display(...)
        }

        ...
    }
}

impl<A: ...> From<A::Error> for AppError {
    fn from(err: A::Error) -> Self {
        AppError::AError(Box::new(err))
    }
}

...

rustc投诉the type parameter `A` is not constrained by the impl trait, self type, or predicates ,我不知道如何修复它。

最后一种可能性是最不冗长的:简单地传播一个 Box<Error> .这是我的B计划。最大的问题是有用的信息丢失了。通过定义 AppError (以及递归地,特定于子系统的错误类型),我得到了一个可怜人的错误回溯。使用 Box<Error>会使错误难以追踪。

是否还有其他选择,或者我的处理方式有误?

最佳答案

错误是什么 the type parameter `A` is not constrained by the impl trait, self type, or predicates意思是?让我们看一个简化的例子:

trait Foo {
    type Error;
}

struct Bar;

struct Baz;

impl Foo for Bar {
    type Error = std::io::Error;
}

impl Foo for Baz {
    type Error = std::io::Error;
}

struct Quux;

impl<T: Foo> From<T::Error> for Quux {
    fn from(err: T::Error) -> Quux {
        Quux
    }
}

问题是类型 U可以匹配T::Error对于多个 T .在这里,例如 std::io::Error将同时匹配 Bar::ErrorBaz::Error .那么,编译器应该为 T 选择哪种类型? ?

解决方案很简单:不要使用 A::ErrorB::Error ;相反,定义 AB直接成为错误类型。当您使用 AppErrorApp 内, 你会返回 AppError<A::Error, B::Error>而不是 AppError<A, B> .是的,你必须重复 ::Error到处;我认为没有解决方案。

关于generics - 无法创建简洁和通用的错误类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43834456/

相关文章:

Java 泛型 : Wildcard capture misunderstanding

C 通用打印数组函数 - 打印字符串数组

c - 如何检查数组C中元素的数据类型

python - python 字节数组在哪里使用?

TypeScript 和 Koa 2 : async/await issue with Global Error Handler

javascript - 如何编写可重用的错误?

error-handling - 如何将 rust Try trait 与 Option NoneError 一起使用?

java - 如果需要抽象接口(interface),则不允许在函数参数中提供已实现的接口(interface)

c# - 类型参数的构造函数签名约束

python - 获取字典中键的类型