了解特征和对象安全
Understanding Traits and Object Safety
我正在努力学习对象安全的基础知识。如果我有这个代码
struct S {
x: i32,
}
trait Trait: Sized {
fn f(&self) -> i32
where
Self: Sized;
}
fn object_safety_dynamic(x: Trait) {}
我收到
error[E0038]: the trait `Trait` cannot be made into an object
--> src/lib.rs:11:29
|
5 | trait Trait: Sized {
| ----- ----- ...because it requires `Self: Sized`
| |
| this trait cannot be made into an object...
...
11 | fn object_safety_dynamic(x: Trait) {}
| ^^^^^ the trait `Trait` cannot be made into an object
当我添加或删除 : Sized
作为超特性或 f
的绑定时,我收到略有不同的错误消息。
谁能解释一下:
为什么这个特定示例不起作用? Trait Objects 章指出:
So what makes a method object-safe? Each method must require that Self: Sized
这不是应验了吗?
Trait: Sized
和where Self: Sized
有什么区别? (嗯,是的,一个是继承trait,另一个是参数绑定,但是从Rust的trait对象角度?
我必须让 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;
}
使 Trait
成为 Sized
的超类型没有帮助 - 事实上,正如错误消息所说,这是不允许的。 Trait
的每个实现仍将具有 不同的 大小,因此您的函数 object_safety_dynamic
无法编译。此处不能使用单态化,因为没有泛型参数,因此编译后的函数必须适用于 Trait
.
的 all 实现
但是,引用 do 具有固定大小,因此将参数转换为引用是可行的:
trait Trait {
fn f(&self) -> i32;
}
fn object_safety_dynamic(x: &Trait) {}
特征对象总是某种引用,例如一个 Box<T>
或 &T
。这正是因为特征实现的大小会有所不同,而引用类型具有已知的固定大小。
Why does this particular example not work? The chapter Trait Objects
states:
So what makes a method object-safe? Each method must require that Self: Sized
这不是应验了吗?
这个问题真的是:什么是特征对象?
一个特征对象是面向对象范例中的一个接口:
- 它公开了一组有限的方法,
- 应用于未知的具体类型。
应用操作的具体类型是未知的,这就是人们使用 trait 对象的具体原因,因为它允许以统一的方式操纵一组异构类型 直至程序集等级.
然而,具体类型未知的事实意味着包含内存的内存区域的大小也未知;因此,特征对象只能在 reference 或 pointer 之后进行操作,例如 &dyn TraitObject
、&mut dyn TraitObject
或 Box<dyn TraitObject>
例如。
在内存级别,它们中的每一个都以相同的方式表示:
- 指向虚拟 table 的指针,它是一种结构,在固定偏移量处为特征对象的每个“方法”保存一个函数指针,
- 指向对象实际数据的指针。
What is the difference between Trait: Sized
and where Self: Sized
? (Well, yes, one inherits the trait the other one is a parameter bound, but from Rust's trait object perspective?)
Rust 中没有继承。在两种情况下,它们都是边界:
Trait: Sized
声明特征本身只能为已经实现 Sized
, 的类型实现
fn method(&self) where Self: Sized
声明只有实现 Sized
的类型才能实现此方法。
注意:实现trait时,所有的方法最终都必须有一个定义;因此后者只有在为具有 Self: Sized
绑定的方法提供默认实现时才真正有用,如 is shown here.
What is the preferred change I had to make object_safety_dynamic
work?
您必须通过引用或指针获取特征对象。使用引用还是指针取决于是否要转移所有权。
我正在努力学习对象安全的基础知识。如果我有这个代码
struct S {
x: i32,
}
trait Trait: Sized {
fn f(&self) -> i32
where
Self: Sized;
}
fn object_safety_dynamic(x: Trait) {}
我收到
error[E0038]: the trait `Trait` cannot be made into an object
--> src/lib.rs:11:29
|
5 | trait Trait: Sized {
| ----- ----- ...because it requires `Self: Sized`
| |
| this trait cannot be made into an object...
...
11 | fn object_safety_dynamic(x: Trait) {}
| ^^^^^ the trait `Trait` cannot be made into an object
当我添加或删除 : Sized
作为超特性或 f
的绑定时,我收到略有不同的错误消息。
谁能解释一下:
为什么这个特定示例不起作用? Trait Objects 章指出:
So what makes a method object-safe? Each method must require that
Self: Sized
这不是应验了吗?
Trait: Sized
和where Self: Sized
有什么区别? (嗯,是的,一个是继承trait,另一个是参数绑定,但是从Rust的trait对象角度?我必须让
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;
}
使 Trait
成为 Sized
的超类型没有帮助 - 事实上,正如错误消息所说,这是不允许的。 Trait
的每个实现仍将具有 不同的 大小,因此您的函数 object_safety_dynamic
无法编译。此处不能使用单态化,因为没有泛型参数,因此编译后的函数必须适用于 Trait
.
但是,引用 do 具有固定大小,因此将参数转换为引用是可行的:
trait Trait {
fn f(&self) -> i32;
}
fn object_safety_dynamic(x: &Trait) {}
特征对象总是某种引用,例如一个 Box<T>
或 &T
。这正是因为特征实现的大小会有所不同,而引用类型具有已知的固定大小。
Why does this particular example not work? The chapter Trait Objects states:
So what makes a method object-safe? Each method must require that
Self: Sized
这不是应验了吗?
这个问题真的是:什么是特征对象?
一个特征对象是面向对象范例中的一个接口:
- 它公开了一组有限的方法,
- 应用于未知的具体类型。
应用操作的具体类型是未知的,这就是人们使用 trait 对象的具体原因,因为它允许以统一的方式操纵一组异构类型 直至程序集等级.
然而,具体类型未知的事实意味着包含内存的内存区域的大小也未知;因此,特征对象只能在 reference 或 pointer 之后进行操作,例如 &dyn TraitObject
、&mut dyn TraitObject
或 Box<dyn TraitObject>
例如。
在内存级别,它们中的每一个都以相同的方式表示:
- 指向虚拟 table 的指针,它是一种结构,在固定偏移量处为特征对象的每个“方法”保存一个函数指针,
- 指向对象实际数据的指针。
What is the difference between
Trait: Sized
and whereSelf: Sized
? (Well, yes, one inherits the trait the other one is a parameter bound, but from Rust's trait object perspective?)
Rust 中没有继承。在两种情况下,它们都是边界:
Trait: Sized
声明特征本身只能为已经实现Sized
, 的类型实现
fn method(&self) where Self: Sized
声明只有实现Sized
的类型才能实现此方法。
注意:实现trait时,所有的方法最终都必须有一个定义;因此后者只有在为具有 Self: Sized
绑定的方法提供默认实现时才真正有用,如 is shown here.
What is the preferred change I had to make
object_safety_dynamic
work?
您必须通过引用或指针获取特征对象。使用引用还是指针取决于是否要转移所有权。