我很难尝试创建一个既通用又不会演变成一团糟的错误类型 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::Error
和 Baz::Error
.那么,编译器应该为 T
选择哪种类型? ?
解决方案很简单:不要使用 A::Error
和 B::Error
;相反,定义 A
和 B
直接成为错误类型。当您使用 AppError
在 App
内, 你会返回 AppError<A::Error, B::Error>
而不是 AppError<A, B>
.是的,你必须重复 ::Error
到处;我认为没有解决方案。
关于generics - 无法创建简洁和通用的错误类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43834456/