|
|
|
@ -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" />
|
|
|
|
|
|
|
|
|
|
结合上文的内容和这张图可以了解:
|
|
|
|
|
|
|
|
|
|
- **特征对象大小不固定**:这是因为,对于特征 `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
|
|
|
|
|
|
|
|
|
|
在 Rust 中,有两个`self`,一个指代当前的实例对象,一个指代特征或者方法类型的别名:
|
|
|
|
|