我正在努力解决对象安全的基础问题。如果我有这个代码
struct S {
x: i32
}
trait Trait: Sized {
fn f(&self) -> i32 where Self: Sized;
}
fn object_safety_dynamic(x: Trait) {}
我收到了
fn object_safety_dynamic(x: Trait) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `traits::Trait` cannot be made into an object
= note: the trait cannot require that `Self : Sized`
当添加/更改:Sized
作为特征的继承或f
的界限时,我会收到略有不同的错误消息。
有人可以解释一下:
为什么这个特定的例子不起作用?章节Trait Objects陈述“那么什么使方法对象安全?每种方法都必须要求Self: Sized
”。是不是满足了?
Trait: Sized
和where Self: Sized
之间有什么区别? (嗯,是的,一个继承了特性,另一个是参数绑定,但是从Rust的特征对象的角度来看?
我必须让object_safety_dynamic
工作的首选更改是什么?
如果重要,我正在使用rustc 1.19.0-nightly (01951a61a 2017-05-20)
。
修改 - 跟进:
解决有关固定尺寸的评论。
trait TraitB {
fn f(&self) -> i32 where Self: Sized;
fn g<T>(&self, t:T) -> i32 where Self: Sized;
}
答案 0 :(得分:7)
为什么这个特定的例子不起作用? Trait Objects一章说明“那么什么使方法对象安全?每种方法都必须要求Self:Sized”。这不是完成了吗?
这个问题确实是:什么是特质对象?
特征对象是面向对象范例中的一个界面:
应用操作的具体类型未知的事实是具体使用特征对象的原因,因为它允许以统一的方式操作异构的一组类型直到汇编级别
然而,具体类型未知的事实意味着包含内存的内存区域的大小也未知;因此,Trait对象只能在引用或指针后面操作,例如&TraitObject
,&mut TraitObject
或Box<TraitObject>
。< / p>
在内存级别,每个都表示相同:
Trait:Sized和Self:Sized之间有什么区别? (嗯,是的,一个继承了特征,另一个是参数绑定,但是从Rust的特征对象的角度来看?)
Rust中没有继承。在两个案例中, bounds :
Trait: Sized
表示特征本身只能针对已经实现Sized
的类型实现,fn method(&self) where Self: Sized
表示只有实现Sized
的类型才能实现此方法。 注意:在实现特征时,所有方法都必须最终有一个定义;因此,如果为Self: Sized
绑定的方法提供默认实现,is shown here,则后者才真正有用。
我必须让
object_safety_dynamic
工作的首选更改是什么?
您必须通过引用或指针获取Trait对象。是否使用引用或指针取决于您是否要转移所有权。
答案 1 :(得分:3)
使<base href="/">
成为Trait
的超类型并没有帮助 - 事实上它是不允许的,正如错误消息所示。 Sized
的每个实现仍然具有不同的大小,因此无法编译函数Trait
。这里不能使用单态化,因为没有泛型参数,因此编译的函数必须适用于 object_safety_dynamic
的所有实现。
但是,引用 do 具有固定的大小,因此将参数变为引用将起作用:
Trait
特质对象总是某种类型的引用,例如trait Trait {
fn f(&self) -> i32;
}
fn object_safety_dynamic(x: &Trait) {}
或Box<T>
。这正是因为特征的实现大小不同,而引用类型具有已知的固定大小。