mirror of
https://github.com/rust-lang-cn/book-cn.git
synced 2025-02-02 15:28:40 +08:00
docs: reformat the document
This commit is contained in:
parent
fa2702d485
commit
90a4b2a7b4
@ -68,7 +68,7 @@ impl AveragedCollection {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">示例 17-2: 在`AveragedCollection` 结构体上实现了`add`、`remove` 和 `average` 公有方法</span>
|
||||
<span class="caption">示例 17-2: 在 `AveragedCollection` 结构体上实现了 `add`、`remove` 和 `average` 公有方法</span>
|
||||
|
||||
公有方法 `add`、`remove` 和 `average` 是修改 `AveragedCollection` 实例的唯一方式。当使用 `add` 方法把一个元素加入到 `list` 或者使用 `remove` 方法来删除时,这些方法的实现同时会调用私有的 `update_average` 方法来更新 `average` 字段。
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
### 定义通用行为的 trait
|
||||
|
||||
为了实现 `gui` 所期望的行为,让我们定义一个 `Draw` trait,其中包含名为 `draw` 的方法。接着可以定义一个存放 **trait 对象**(*trait object*) 的 vector。trait 对象指向一个实现了我们指定 trait 的类型的实例,以及一个用于在运行时查找该类型的trait方法的表。我们通过指定某种指针来创建 trait 对象,例如 `&` 引用或 `Box<T>` 智能指针,还有 `dyn` keyword, 以及指定相关的 trait(第 19 章 [““动态大小类型和 `Sized` trait”][dynamically-sized] 部分会介绍 trait 对象必须使用指针的原因)。我们可以使用 trait 对象代替泛型或具体类型。任何使用 trait 对象的位置,Rust 的类型系统会在编译时确保任何在此上下文中使用的值会实现其 trait 对象的 trait。如此便无需在编译时就知晓所有可能的类型。
|
||||
为了实现 `gui` 所期望的行为,让我们定义一个 `Draw` trait,其中包含名为 `draw` 的方法。接着可以定义一个存放 **trait 对象**(*trait object*) 的 vector。trait 对象指向一个实现了我们指定 trait 的类型的实例,以及一个用于在运行时查找该类型的 trait 方法的表。我们通过指定某种指针来创建 trait 对象,例如 `&` 引用或 `Box<T>` 智能指针,还有 `dyn` keyword, 以及指定相关的 trait(第 19 章 [“动态大小类型和 `Sized` trait”][dynamically-sized] 部分会介绍 trait 对象必须使用指针的原因)。我们可以使用 trait 对象代替泛型或具体类型。任何使用 trait 对象的位置,Rust 的类型系统会在编译时确保任何在此上下文中使用的值会实现其 trait 对象的 trait。如此便无需在编译时就知晓所有可能的类型。
|
||||
|
||||
之前提到过,Rust 刻意不将结构体与枚举称为 “对象”,以便与其他语言中的对象相区别。在结构体或枚举中,结构体字段中的数据和 `impl` 块中的行为是分开的,不同于其他语言中将数据和行为组合进一个称为对象的概念中。trait 对象将数据和行为两者相结合,从这种意义上说 **则** 其更类似其他语言中的对象。不过 trait 对象不同于传统的对象,因为不能向 trait 对象增加数据。trait 对象并不像其他语言中的对象那么通用:其(trait 对象)具体的作用是允许对通用行为进行抽象。
|
||||
|
||||
@ -221,7 +221,7 @@ error[E0277]: the trait bound `std::string::String: gui::Draw` is not satisfied
|
||||
|
||||
### trait 对象执行动态分发
|
||||
|
||||
回忆一下第 10 章 [“泛型代码的性能”][performance-of-code-using-generics] 部分讨论过的,当对泛型使用 trait bound 时编译器所进行单态化处理:编译器为每一个被泛型类型参数代替的具体类型生成了非泛型的函数和方法实现。单态化所产生的代码进行 **静态分发**(*static dispatch*)。静态分发发生于编译器在编译时就知晓调用了什么方法的时候。这与 **动态分发** (*dynamic dispatch*)相对,这时编译器在编译时无法知晓调用了什么方法。在动态分发的情况下,编译器会生成在运行时确定调用了什么方法的代码。
|
||||
回忆一下第 10 章 [“泛型代码的性能”][performance-of-code-using-generics] 部分讨论过的,当对泛型使用 trait bound 时编译器所进行单态化处理:编译器为每一个被泛型类型参数代替的具体类型生成了非泛型的函数和方法实现。单态化所产生的代码进行 **静态分发**(*static dispatch*)。静态分发发生于编译器在编译时就知晓调用了什么方法的时候。这与 **动态分发**(*dynamic dispatch*)相对,这时编译器在编译时无法知晓调用了什么方法。在动态分发的情况下,编译器会生成在运行时确定调用了什么方法的代码。
|
||||
|
||||
当使用 trait 对象时,Rust 必须使用动态分发。编译器无法知晓所有可能用于 trait 对象代码的类型,所以它也不知道应该调用哪个类型的哪个方法实现。为此,Rust 在运行时使用 trait 对象中的指针来知晓需要调用哪个方法。动态分发也阻止编译器有选择的内联方法代码,这会相应的禁用一些优化。尽管在编写示例 17-5 和可以支持示例 17-9 中的代码的过程中确实获得了额外的灵活性,但仍然需要权衡取舍。
|
||||
|
||||
@ -268,7 +268,5 @@ error[E0038]: the trait `std::clone::Clone` cannot be made into an object
|
||||
这意味着不能以这种方式使用此 trait 作为 trait 对象。如果你对对象安全的更多细节感兴趣,请查看 [Rust RFC 255]。
|
||||
|
||||
[Rust RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
|
||||
|
||||
[performance-of-code-using-generics]:
|
||||
ch10-01-syntax.html#performance-of-code-using-generics
|
||||
[performance-of-code-using-generics]: ch10-01-syntax.html#performance-of-code-using-generics
|
||||
[dynamically-sized]: ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
|
||||
|
@ -326,7 +326,7 @@ fn main() {
|
||||
|
||||
#### 使用嵌套的 `_` 忽略部分值
|
||||
|
||||
也可以在一个模式内部使用`_` 忽略部分值,例如,当只需要测试部分值但在期望运行的代码中没有用到其他部分时。示例 18-18 展示了负责管理设置值的代码。业务需求是用户不允许覆盖现有的自定义设置,但是可以取消设置,也可以在当前未设置时为其提供设置。
|
||||
也可以在一个模式内部使用 `_` 忽略部分值,例如,当只需要测试部分值但在期望运行的代码中没有用到其他部分时。示例 18-18 展示了负责管理设置值的代码。业务需求是用户不允许覆盖现有的自定义设置,但是可以取消设置,也可以在当前未设置时为其提供设置。
|
||||
|
||||
```rust
|
||||
let mut setting_value = Some(5);
|
||||
|
Loading…
Reference in New Issue
Block a user