[英]Apply trait bounds to associated type
假设我有这样的特征:
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()))
}
}
这很好用。
现在想象一下,我想使用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()))
}
}
}
然而,这不起作用。 我尝试了各种不同的方式来表达这一点,但我无法弄清楚如何说“这个 TryFrom impl,在错误的情况下,返回一些 impls InternalError 的东西”。
任何有关如何正确执行此操作的建议将不胜感激。 谢谢!
这个 TryFrom impl,在错误的情况下,返回一些 impls InternalError
TryFrom
想在编译时知道返回了什么样的错误。 您似乎想在运行时决定类型。
假设FirstError
和SecondError
都实现了InternalError
。
在这种情况下
impl TryFrom<u32> for MyU16 {
type Error = FirstError;
fn try_from(value: u32) -> Result<Self, FirstError> {
/*...*/
}
}
会编译,但当然try_from
只能返回FirstError
。
但是,如果您想在运行时在FirstError
和SecondError
之间做出决定。 相关的错误类型(不是特征)需要能够同时包含两者。
impl TryFrom<u32> for MyU16 {
type Error = Box<dyn InternalError>;
fn try_from(value: u32) -> Result<Self, Box<dyn InternalError>> {
/*...*/
Box::new(FirstError::internal("invalid".to_string()))
}
}
这也暗示了为什么enum
是 Rust 中表示错误的惯用方式:通常你在编译时不知道会出现什么问题。 因此,一个可以列出所有状态的enum
可以让用户清楚地知道可能出现的问题,并且在许多情况下,您可以在没有额外堆分配的情况下创建错误。
它无法编译的原因是impl
声明中的类型参数必须出现在实现类型( impl<T> Foo<T>
)或实现的特征( impl<T> MyTrait<T> for Foo
)。 您不能只impl<T> for Foo
并且只在impl
块中再次提及T
。
正如扩展错误所暗示的那样,有一种解决方法将幻像类型引入实现类型,但您可能不喜欢它使您的代码看起来如何:
use std::marker::PhantomData;
struct MyU16<T>(pub u16, PhantomData<T>);
impl<E: InternalError> TryFrom<u32> for MyU16<E> {
type Error = E;
fn try_from(value: u32) -> Result<Self, Self::Error> {
if value < u16::MAX as u32 {
Ok(MyU16(value as u16, PhantomData))
} else {
Err(E::internal("invalid".to_string()))
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.