Rust 为什么在这个特征中“大小”界限是必要的?
我有两个相关功能的特点:Rust 为什么在这个特征中“大小”界限是必要的?,rust,traits,Rust,Traits,我有两个相关功能的特点: trait WithConstructor: Sized { fn new_with_param(param: usize) -> Self; fn new() -> Self { Self::new_with_param(0) } } 为什么第二个方法(new())的默认实现会强制我将size绑定到类型上?我想这是因为堆栈指针操作,但我不确定 如果编译器需要知道堆栈上分配内存的大小, 为什么以下示例不要求T使用s
trait WithConstructor: Sized {
fn new_with_param(param: usize) -> Self;
fn new() -> Self {
Self::new_with_param(0)
}
}
为什么第二个方法(new()
)的默认实现会强制我将size
绑定到类型上?我想这是因为堆栈指针操作,但我不确定
如果编译器需要知道堆栈上分配内存的大小,
为什么以下示例不要求T
使用size
struct SimpleStruct<T> {
field: T,
}
fn main() {
let s = SimpleStruct { field: 0u32 };
}
struct SimpleStruct{
字段:T,
}
fn main(){
设s=SimpleStruct{field:0u32};
}
让我们看看如果您使用非大小的类型执行此操作会发生什么
new()。但是,除非类型已调整大小,否则应该移动多少字节?我们根本不知道。这就是为什么移动语义需要size
类型
注意:各种框
都是专门为这个问题提供运行时服务的。正如您可能已经知道的,Rust中的类型可以调整大小,也可以不调整大小。顾名思义,未大小化的类型没有存储编译器已知的这种类型的值所需的大小。例如,[u32]
是u32
s的非大小数组;因为元素的数量没有在任何地方指定,所以编译器不知道它的大小。另一个示例是裸特征对象类型,例如,Display
,当它直接用作类型时:
let x: Display = ...;
在这种情况下,编译器不知道这里实际使用的是哪种类型,它被擦除,因此它不知道这些类型的值的大小。上述行无效-在不知道其大小的情况下,无法生成局部变量(以便在堆栈上分配足够的字节),并且无法将未大小类型的值作为参数传递到函数中或从函数返回
但是,可以通过指针使用未大小的类型,该指针可以携带附加信息—片的可用数据长度(&[u32]
)或指向虚拟表的指针(框
)。因为指针总是有一个固定的已知大小,所以它们可以存储在局部变量中,并传递到函数中或从函数中返回
给定任何具体的类型,你总是可以说它是大小的还是不大小的。然而,对于泛型,出现了一个问题-是否有一些类型参数大小
fn generic_fn<T>(x: T) -> T { ... }
这是因为在绝大多数情况下,您希望调整通用参数的大小。但是,有时您可能希望选择退出Sizeness,这可以通过?Sized
绑定完成:
fn generic_fn<T: ?Sized>(x: &T) -> u32 { ... }
然而,这只是出于方便和实用的目的。可以将特征定义为始终采用一个类型参数,而不指定实现特征的类型:
// this is not actual Rust but some Rust-like language
trait A<T> {
fn do_something(t: &T);
}
struct X;
impl A<X> {
fn do_something(t: &X) {}
}
这就是规模问题的所在。Self
参数的大小是否合适
事实证明,在Rust中,Self
的默认大小不是。每个特质都有一个隐式的?大小绑定在自我上。之所以需要这样做,其中一个原因是,有很多特性可以用于未大小的类型,并且仍然有效。例如,任何只包含只通过引用获取并返回Self
的方法的trait都可以用于未大小的类型。你可以阅读更多关于动机的文章
当您只定义特征及其方法的签名时,大小不是问题。因为这些定义中没有实际的代码,编译器不能假设任何东西。但是,当您开始编写使用此特性的泛型代码时(其中包括默认方法,因为它们采用隐式Self
参数),您应该考虑大小。因为默认情况下,Self
没有大小,所以默认的trait方法不能按值返回Self
,也不能按值将其作为参数。因此,您需要指定默认情况下必须调整Self
的大小:
trait A: Sized { ... }
或者,您可以指定仅当Self
的大小为:
trait WithConstructor {
fn new_with_param(param: usize) -> Self;
fn new() -> Self
where
Self: Sized,
{
Self::new_with_param(0)
}
}
但是为什么它不抱怨新的带有_param的
?它还需要在调用方的堆栈上保留适当的空间。所以我的想法是正确的,但是为什么在泛型结构中不需要Size
??我更新了这个问题。@Matthieu M.new\u with_param
只是一个trait方法定义,而不是一个实现。@AndreaP:astruct
在默认情况下总是size
。我想我明白了。显然,泛型类型T
(不是结构)在默认情况下被视为针对结构的大小(除非您放置?size
),而不是针对特征。谢谢你这么完整的回答。我不知道所有的“默认大小,但自我不是”部分。“这就是我感到困惑的主要原因。”不幸的是,弗拉基米尔和铁锈书的章节已经冻结。否则你一定要考虑在那里提出你的解释。
trait A {
fn do_something(t: &Self);
}
trait A: Sized { ... }
trait WithConstructor {
fn new_with_param(param: usize) -> Self;
fn new() -> Self
where
Self: Sized,
{
Self::new_with_param(0)
}
}