背景
今天在群里看到有人贴了一段报错代码:
pub trait VertexList<T> {fn new() -> Self;fn with_capacity(_cap: usize) -> Self {Self::new() // here!}fn push(&mut self, v: T);}
报错:
error[E0277]: the size for values of type `Self` cannot be known at compilation time--> src/timer.rs:29:9|29 | Self::new()| ^^^^^^^^^ doesn't have a size known at compile-time|= help: the trait `std::marker::Sized` is not implemented for `Self`= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>= note: the return type of a function must have a statically known sizehelp: consider further restricting `Self`|28 | fn with_capacity(_cap: usize) -> Self where Self: std::marker::Sized {| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
编译器很贴心,告诉你该怎么改。编译器要给 with_capacity() 的默认实现分配栈空间(new方法没有默认实现,因此这里没有报错),需要在编译期确定Self::new()的大小,而且这个大小不能变化,也就是这里的返回值满足 Sized 。
Sized
Sized 是一个自动实现的trait, 表示类型在编译期可以确定一个常量长度,如:类型 &u8, [u8; 10], Vec<[u8]> 都是 Sized , 但 str, [u8] 是 ?Sized 。
它有如下特点:
- 类型参数
T默认是T: Sized。如果要表示允许固定或者非固定长度类型,要显式写成T: ?Sized。 - trait的定义中有一个隐含的
Self类型,指代实现该trait的类型(在声明时不确定是哪个类型)。此处的Self默认是Self: ?Sized,这与上一条的恰好相反。所以在例子中,需要手动添加Where Self: Sized。Rust认为所有size的类型都可以实现trait,因此从语义上默认trait的Self的长度不一定是常量。 - 因为语义上排除了trait的Self不是Sized,我们可以在trait定义中复用
Self:Sized来方法加入trait obj的vtable, 或者禁止trait生成trait object。
解决办法
// 方法1pub trait VertexList<T>: Sized {// ..}// 方法2pub trait VertexList<T> {fn with_capacity(_cap: usize) -> Self where Self: Sized{Self::new()}}
