|
|
@ -287,13 +287,13 @@ fn main() {
|
|
|
|
当理解了 `self` 与 `Self` 的区别后,我们再来看看何为对象安全。
|
|
|
|
当理解了 `self` 与 `Self` 的区别后,我们再来看看何为对象安全。
|
|
|
|
|
|
|
|
|
|
|
|
## 特征对象的限制
|
|
|
|
## 特征对象的限制
|
|
|
|
不是所有特征都能拥有特征对象,只有对象安全的特征才行。当一个特征的所有方法都有如下属性时,该对象才是安全的:
|
|
|
|
不是所有特征都能拥有特征对象,只有对象安全的特征才行。当一个特征的所有方法都有如下属性时,它的对象才是安全的:
|
|
|
|
- 方法的返回类型不能是`Self`
|
|
|
|
- 方法的返回类型不能是 `Self`
|
|
|
|
- 方法没有任何泛型参数
|
|
|
|
- 方法没有任何泛型参数
|
|
|
|
|
|
|
|
|
|
|
|
对象安全对于特征对象是必须的,因为一旦有了特征对象,就不再需要知道实现该特征的具体类型是什么了。如果特征方法返回具体的 `Self` 类型,但是特征对象忘记了其真正的类型,那这个 `Self` 就非常尴尬,因为没人知道它是谁了。同理对于泛型类型参数来说,当使用特征时其会放入具体的类型参数:此具体类型变成了实现该特征的类型的一部分。当使用特征对象时其具体类型被抹去了,故而无从得知放入泛型参数类型到底是什么。
|
|
|
|
对象安全对于特征对象是必须的,因为一旦有了特征对象,就不再需要知道实现该特征的具体类型是什么了。如果特征方法返回了具体的 `Self` 类型,但是特征对象忘记了其真正的类型,那这个 `Self` 就非常尴尬,因为没人知道它是谁了。但是对于泛型类型参数来说,当使用特征时其会放入具体的类型参数:此具体类型变成了实现该特征的类型的一部分。而当使用特征对象时其具体类型被抹去了,故而无从得知放入泛型参数类型到底是什么。
|
|
|
|
|
|
|
|
|
|
|
|
标准库中的 `Clone` 特征就不符合对象安全的要求:
|
|
|
|
标准库中的 `Clone` 特征就不符合对象安全的要求:
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
```rust
|
|
|
|
pub trait Clone {
|
|
|
|
pub trait Clone {
|
|
|
@ -305,7 +305,7 @@ pub trait Clone {
|
|
|
|
|
|
|
|
|
|
|
|
`String` 类型实现了 `Clone` 特征, `String` 实例上调用 `clone` 方法时会得到一个 `String` 实例。类似的,当调用 `Vec<T>` 实例的 `clone` 方法会得到一个 `Vec<T>` 实例。`clone` 的签名需要知道什么类型会代替 `Self`,因为这是它的返回值。
|
|
|
|
`String` 类型实现了 `Clone` 特征, `String` 实例上调用 `clone` 方法时会得到一个 `String` 实例。类似的,当调用 `Vec<T>` 实例的 `clone` 方法会得到一个 `Vec<T>` 实例。`clone` 的签名需要知道什么类型会代替 `Self`,因为这是它的返回值。
|
|
|
|
|
|
|
|
|
|
|
|
如果违反了对象安全的规则,编译器会提示你。例如,如果尝试使用之前的`Screen`结构体来存放实现了 `Clone`特征的类型:
|
|
|
|
如果违反了对象安全的规则,编译器会提示你。例如,如果尝试使用之前的 `Screen` 结构体来存放实现了 `Clone` 特征的类型:
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
```rust
|
|
|
|
pub struct Screen {
|
|
|
|
pub struct Screen {
|
|
|
|