假设我有这样一个特质:
trait InternalError {
fn internal(error: String) -> Self;
}
如果我想在函数中使用它,我可以这样做:
struct MyU16(pub u16);
fn my_try_from<E: InternalError>(value: u32) -> Result<MyU16, E> {
if value < u16::MAX as u32 {
Ok(MyU16(value as u16))
} else {
Err(E::internal("invalid".to_string()))
}
}
This works just fine.
现在假设我不使用自己的函数,而是使用TryFrom
:
impl<E: InternalError> TryFrom<u32> for MyU16 {
type Error = E;
fn try_from(value: u32) -> Result<Self, Self::Error> {
if value < u16::MAX as u32 {
Ok(MyU16(value as u16))
} else {
Err(E::internal("invalid".to_string()))
}
}
}
我尝试了各种不同的表达方式,但我不知道如何表达"在错误情况下,this TryFrom impl返回impls InternalError的内容"。
我该怎么做呢?
2条答案
按热度按时间9gm1akwq1#
在错误情况下,此TryFrom实现将返回暗示InternalError的内容
TryFrom
希望在编译时知道返回的错误类型,而您似乎希望在运行时决定类型。假设
FirstError
和SecondError
都实现了InternalError
。在这种情况下
将编译,但当然
try_from
只能返回FirstError
。如果你想在运行时在
FirstError
和SecondError
之间做出决定,那么相关的错误type(不是trait)需要能够同时包含这两个错误。这也暗示了为什么
enum
是Rust中表示错误的惯用方法:通常你在编译时知道什么可能出错,但你还不知道什么会出错(如果有的话)。实际发生的错误只有在运行时才知道。因此,让类型能够表示一组潜在的错误,而示例是一个特定的错误是一个好主意。enum
迭代符合这一要求,它向用户清楚地说明了可能出错的地方,并且在许多情况下允许您创建错误而无需额外的堆分配。lsmd5eda2#
它不能编译的原因是
impl
声明中的type参数必须出现在 implementing type(impl<T> Foo<T>
)或 implemented trait(impl<T> MyTrait<T> for Foo
)中,你不能只写impl<T> for Foo
,然后在impl
代码块中再次提到T
。正如扩展的错误所建议的那样,有一种变通方法可以将幻像类型引入到实现类型中,但您可能不喜欢它使代码看起来的样子: