定义通用特征时出现未知大小编译错误
Unknown size compile error when defining generic trait
作为 Rust 编程的初学者,我对 Size trait 与通用 traits 的结合有点困惑。
我的自定义特征定义了一个方法,它接受两个对象并将它们组合成一个新对象。因为原始对象在组合后过期,方法应该取得参数的所有权。
我还 return 一个带有自定义错误类型的结果,因为组合 可能会失败 并且我想向调用者提供失败的原因。
相关特征是:
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>
),但这没有用。我也在类型别名声明中尝试了同样的方法,也无济于事。
我missing/overlooking是什么东西吗?
dyn Combinable<T>
是一个 unsized 类型(因为特征可以通过任何类型的方式实现,所以值的大小在编译时是未知的)。这反过来意味着 Result<dyn Combinable<T>, ...>
也未调整大小。未确定大小的类型相当有限,其中一个限制是它们不能按值返回。您只能通过某种间接方式(引用、指针等)有意义地处理未确定大小的类型
通常的解决方法是 box 他们:
type CombinationResult<T> = std::result::Result<Box<dyn Combinable<T>>, CombinationError>
// ^^^
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>;
第二种解决方案是将合并的项目移动到 returned 值中。如果没有泛型、特征或错误处理,我们将如何做到这一点:
struct ItemA {}
struct ItemB {}
impl ItemA {
fn combine (self, other: ItemB) -> CombinedAB {
CombinedAB { a: self, b: other }
}
}
struct CombinedAB {
a: ItemA,
b: ItemB,
}
请注意,combine
方法 return 的类型取决于输入的类型。如果我们想将 combine
方法抽象成一个特征,我们不能在声明特征时固定 return 类型,因为我们还不知道将在实现中使用的类型。出于这个原因,我们使用关联类型,这是一种说法:“此类型将由实现指定”。这是使用特征和泛型的相同示例:
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 }
}
}
请注意,我为参数使用了泛型类型,为 returned 值使用了关联类型。 提供了更多详细信息并解释了何时使用其中之一。
当然,如果 combine
方法应该 return 所有输入的相同 具体 类型,那么您可以完全省去关联类型:
struct Combined {}
pub trait Combinable<T> {
fn combine(self, other: T) -> Combined;
}
作为 Rust 编程的初学者,我对 Size trait 与通用 traits 的结合有点困惑。 我的自定义特征定义了一个方法,它接受两个对象并将它们组合成一个新对象。因为原始对象在组合后过期,方法应该取得参数的所有权。 我还 return 一个带有自定义错误类型的结果,因为组合 可能会失败 并且我想向调用者提供失败的原因。
相关特征是:
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>
),但这没有用。我也在类型别名声明中尝试了同样的方法,也无济于事。
我missing/overlooking是什么东西吗?
dyn Combinable<T>
是一个 unsized 类型(因为特征可以通过任何类型的方式实现,所以值的大小在编译时是未知的)。这反过来意味着 Result<dyn Combinable<T>, ...>
也未调整大小。未确定大小的类型相当有限,其中一个限制是它们不能按值返回。您只能通过某种间接方式(引用、指针等)有意义地处理未确定大小的类型
通常的解决方法是 box 他们:
type CombinationResult<T> = std::result::Result<Box<dyn Combinable<T>>, CombinationError>
// ^^^
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>;
第二种解决方案是将合并的项目移动到 returned 值中。如果没有泛型、特征或错误处理,我们将如何做到这一点:
struct ItemA {}
struct ItemB {}
impl ItemA {
fn combine (self, other: ItemB) -> CombinedAB {
CombinedAB { a: self, b: other }
}
}
struct CombinedAB {
a: ItemA,
b: ItemB,
}
请注意,combine
方法 return 的类型取决于输入的类型。如果我们想将 combine
方法抽象成一个特征,我们不能在声明特征时固定 return 类型,因为我们还不知道将在实现中使用的类型。出于这个原因,我们使用关联类型,这是一种说法:“此类型将由实现指定”。这是使用特征和泛型的相同示例:
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 }
}
}
请注意,我为参数使用了泛型类型,为 returned 值使用了关联类型。
当然,如果 combine
方法应该 return 所有输入的相同 具体 类型,那么您可以完全省去关联类型:
struct Combined {}
pub trait Combinable<T> {
fn combine(self, other: T) -> Combined;
}