作为 Rust 编程的初学者,我对 Size 特征与通用特征的结合有点困惑。 我的自定义特征定义了一种方法,该方法接受两个对象并将它们组合成一个新对象。由于原始对象在组合后就会过期,因此方法应该取得参数的所有权。 我还返回带有自定义错误类型的结果,因为组合可能会失败,并且我想向调用者提供失败的原因。
有问题的特征是:
pub trait Combinable<T> {
fn combine(self, other: T) -> CombinationResult<T>;
}
struct CombinationError;
type CombinationResult<T> = std::result::Result<dyn Combinable<T>, CombinationError>
编译此代码时出现以下错误:
error[E0277]: the size for values of type `(dyn Combinable<T> + 'static)` cannot be known at compilation time
|
7 | fn combine(self, other: T) -> CombinationResult<T>;
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
241 | pub enum Result<T, E> {
| - required by this bound in `std::result::Result`
|
= help: the trait `Sized` is not implemented for `(dyn Combinable<T> + 'static)`
我尝试将泛型类型参数 T 限制为 Sized
(即 pub trait Combinable<T: Sized>
)但这不起作用。我也在类型别名声明中尝试了相同的方法,也无济于事。
我是否遗漏/忽略了某些东西?
最佳答案
dyn Combinable<T>
只能用在引用后面( &
、 Box
、 Rc
…)。由于您想要转让组合项目的所有权,因此您有两种选择:
最简单的方法是将结果装箱:
type CombinationResult<T> = std::result::Result<Box<dyn Combinable<T>>, CombinationError>;
但这会以内存分配和间接的形式增加一些开销。或者您可以使用泛型类型来避免间接:
pub trait Combinable<T> {
type Combined;
fn combine(self, other: T) -> CombinationResult<Self::Combined>;
}
pub struct CombinationError;
type CombinationResult<T> = std::result::Result<T, CombinationError>;
第二个解决方案的工作原理是将组合项移动到返回值中。以下是我们在没有泛型、特征和错误处理的情况下如何做到这一点:
struct ItemA {}
struct ItemB {}
impl ItemA {
fn combine (self, other: ItemB) -> CombinedAB {
CombinedAB { a: self, b: other }
}
}
struct CombinedAB {
a: ItemA,
b: ItemB,
}
请注意 combine
返回的类型方法取决于输入的类型。如果我们想抽象combine
方法到特征中,当我们声明特征时,我们无法修复返回类型,因为我们还不知道实现中将使用的类型。因此,我们使用关联类型,这是一种说法:“该类型将由实现指定”。这是使用特征和泛型的相同示例:
pub trait Combinable<T> {
type Combined;
fn combine(self, other: T) -> Self::Combined;
}
struct ItemA {}
struct ItemB {}
struct CombinedAB {
a: ItemA,
b: ItemB,
}
impl Combinable<ItemB> for ItemA {
type Combined = CombinedAB;
fn combine (self, other: ItemB) -> CombinedAB {
CombinedAB { a: self, b: other }
}
}
请注意,我对参数使用了泛型类型,对返回值使用了关联类型。 This question提供更多详细信息并解释何时使用其中之一。
当然,如果 combine
方法应该为所有输入返回相同的具体类型,然后您可以完全放弃关联的类型:
struct Combined {}
pub trait Combinable<T> {
fn combine(self, other: T) -> Combined;
}
关于generics - 定义通用特征时出现未知大小编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65621903/