Add `Trait Object` comments.

pull/552/head
Rustln 3 years ago committed by GitHub
parent 141800826d
commit 3b0de0f9db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -287,6 +287,18 @@ help: function arguments must have a statically known size, borrowed types alway
<img alt="" src="https://pic1.zhimg.com/80/v2-b771fe4cfc6ebd63d9aff42840eb8e67_1440w.jpg" class="center" /> <img alt="" src="https://pic1.zhimg.com/80/v2-b771fe4cfc6ebd63d9aff42840eb8e67_1440w.jpg" class="center" />
结合上文的内容和这张图可以了解:
- **特征对象大小不固定**:这是因为,对于特征 `Draw`,类型 `Button` 可以实现特征 `Draw`,类型 `SelectBox` 也可以实现特征 `Draw`,因此特征没有固定大小
- **几乎总是使用特征对象的引用方式**,如 `&dyn Draw`、`Box<dyn Draw>`
- 虽然特征对象没有固定大小,但它的引用类型的大小是固定的,它由两个指针组成(`ptr` 和 `vptr`),因此占用两个指针大小
- 一个指针 `ptr` 指向实现了特征 `Draw` 的具体类型的实例,也就是当作特征 `Draw` 来用的类型的实例,比如类型 `Button` 的实例、类型 `SelectBox` 的实例
- 另一个指针 `vptr` 指向一个虚表 `vtable``vtable` 中保存了类型 `Button` 或类型 `SelectBox` 的实例对于可以调用的实现于特征 `Draw` 的方法。当调用方法时,直接从 `vtable` 中找到方法并调用。之所以要使用一个 `vtable` 来保存各实例的方法,是因为实现了特征 `Draw` 的类型有多种,这些类型拥有的方法各不相同,当将这些类型的实例都当作特征 `Draw` 来使用时(此时,它们全都看作是特征 `Draw` 类型的实例),有必要区分这些实例各自有哪些方法可调用
简而言之,当类型 `Button` 实现了特征 `Draw` 时,类型 `Button` 的实例对象 `btn` 可以当作特征 `Draw` 的特征对象类型来使用,`btn` 中保存了作为特征对象的数据指针(指向类型 `Button` 的实例数据)和行为指针(指向 `vtable`)。
一定要注意,此时的 `btn` 被当作特征 `Draw` 的特征对象的实例数据,而不再是类型 `Button` 的实例对象,而且 `btn``vtable` 只包含了实现自特征 `Draw` 的那些方法(比如 `draw`),因此 `btn` 只能调用实现于特征 `Draw``draw` 方法,而不能调用类型 `Button` 本身实现的方法和类型 `Button` 实现于其他特征的方法。**也就是说,`btn` 当作哪个特征对象来用,它的 `vtable` 中就包含哪个特征的方法。**
## Self 与 self ## Self 与 self
在 Rust 中,有两个`self`,一个指代当前的实例对象,一个指代特征或者方法类型的别名: 在 Rust 中,有两个`self`,一个指代当前的实例对象,一个指代特征或者方法类型的别名:
@ -361,4 +373,4 @@ error[E0038]: the trait `std::clone::Clone` cannot be made into an object
## 课后练习 ## 课后练习
> [Rust By Practice](https://zh.practice.rs/generics-traits/trait-object.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 > [Rust By Practice](https://zh.practice.rs/generics-traits/trait-object.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。

Loading…
Cancel
Save