Syntax 什么是';其中';特征中的子句是什么?
如果我有此代码:Syntax 什么是';其中';特征中的子句是什么?,syntax,rust,traits,type-bounds,Syntax,Rust,Traits,Type Bounds,如果我有此代码: trait Trait { fn f(&self) -> i32 where Self: Sized; fn g(&self) -> i32; } fn object_safety_dynamic(x: &Trait) { x.f(); // error x.g(); // works } where子句实际上是做什么的 天真地,我在想,where Self:size规定了实现Trait类
trait Trait {
fn f(&self) -> i32 where Self: Sized;
fn g(&self) -> i32;
}
fn object_safety_dynamic(x: &Trait) {
x.f(); // error
x.g(); // works
}
where
子句实际上是做什么的
天真地,我在想,where Self:size
规定了实现Trait
类型的一些内容,比如“如果你为A
类型实现Trait
,那么你的A
类型必须调整大小,也就是说,它可以是i32
,但不能是[i32]
然而,这样的约束更像是trait:size
(如果我错了,请纠正我)
现在我注意到中Self:size
实际上决定了我是否可以从object\u safety\u dynamic
中调用f
或g
我的问题是:
where Self:Sized告诉编译器什么(用简单的英语说)代码>使g()
工作,但f()
不工作
&self
无论如何都是一个参考,不同类型(大小或非大小)的f
和g
之间存在什么编译差异。不管在哪里
,或者类型大小与否,它都会归结为类似于的东西吗
u8
和[u8]
实现Trait。编译器不应该阻止我为[u8]
实现f()
,而不是在调用站点抛出错误吗fn f(&self)->i32,其中self:size代码>
这意味着f
仅为同样实现大小的类型定义。未分级的类型仍然可以实现Trait
,但f
将不可用
在object\u safety\u dynamic
内部,调用x.f()
实际上是在做:(*x.f()
)。虽然x
的大小是因为它是指针,但*x
可能不是,因为它可能是Trait
的任何实现。但是函数中的代码必须适用于任何有效参数,因此不允许在那里调用x.f()
where子句实际上是做什么的
天真地,我在想自我:大小;指示有关类型实现特征的内容,例如“如果为类型A实现特征,则必须调整类型A的大小,即它可以是i32,但不能是[i32]
然而,这样的约束更像是trait:size
这是正确的
但是,在这种情况下,边界仅适用于函数<代码>其中
仅在调用站点检查函数的边界
在幕后发生了什么
rust的语法有一点让人困惑,那就是Trait
可以引用其中任何一种
- 特质
特质;或
- “trait对象”
trait
,它实际上是一个类型,而不是一个对象
size
是一种特性,任何T
类型的size
都可以通过std::mem::size_of:()
将其大小作为常量。未调整大小的类型有str
和[u8]
,它们的内容没有固定的大小
类型Trait
也没有大小。直观地说,这是因为Trait
作为一个类型,由实现TraitTrait
的所有类型值组成,这些值的大小可能不同。这意味着您永远不能拥有Trait
类型的值-您只能通过“胖指针”引用一个值,例如&Trait
或框
等。它们有两个指针大小——一个用于vtable,一个用于数据。大致如下:
struct &Trait {
pub data: *mut (),
pub vtable: *mut (),
}
自动生成以下表单的impl:
impl Trait /* the trait */ for Trait /* the type */ {
fn f(&self) -> i32 where Self: Sized { .. }
fn g(&self) -> i32 {
/* vtable magic: something like (self.vtable.g)(self.data) */
}
}
我到底在告诉编译器什么(用简单的英语):Self:size;这使得g()工作,但f()不工作
请注意,正如我所提到的,Trait
不是size
,因此绑定的Self:size
不满足,因此不能在Self==Trait
的位置调用函数f
特别是:既然&self无论如何都是一个引用,那么对于各种类型(大小或未大小),f和g之间存在什么不同。无论类型在何处或大小是否相同,它是否总是可以归结为类似于_vtable_f_或_g(*self)->i32的东西
类型Trait
始终未调整大小。哪种类型被强制为Trait
,并不重要。使用size
变量调用函数的方法是直接使用它:
fn generic<T: Trait + Sized>(x: &T) { // the `Sized` bound is implicit, added here for clarity
x.f(); // compiles just fine
x.g();
}
fn generic(x:&T){//为清晰起见,此处添加的'size'边界是隐式的
x、 f();//编译得很好
x、 g();
}
为什么我可以为u8和[u8]实现Trait。编译器不应该阻止我为[u8]实现f(),而不是在调用站点抛出错误吗
因为特征不受自身大小的限制,所以函数f
是。因此,没有什么可以阻止您实现该函数-只是函数的边界永远无法满足,因此您永远无法调用它。我认为您的f
和g
方法是错误的x.g()
应该可以工作,而x.f()
将是一个错误。这是因为f
仅为size
的类型定义,但不能保证x
是size
的,因为Trait
的impl
并非所有的s都是。对Trait的约束限制了哪些类型可以实现Trait。将函数的约束放在trait中会限制实现类型可以调用函数。@PeterHall,是的,谢谢!