fixed CH15-02 L07 L22 L72 L114, CH15-03 L09 L13 L39, CH15-04 L65 L94

pull/22/head
Vincent Song 8 years ago
parent fb9edb11b1
commit 7df4f8f544

@ -4,7 +4,7 @@
> <br>
> commit ecc3adfe0cfa0a4a15a178dc002702fd0ea74b3f
第一个智能指针相关的重要 trait 是`Deref`,它允许我们重载`*`,解引用运算符(不同于乘法运算符和全局引用运算符)。重载智能指针的`*`能使访问其后的数据更为方便,在这个部分的稍后介绍解引用强制多态时我们会讨论方便的意义。
第一个智能指针相关的重要 trait 是`Deref`,它允许我们重载`*`,解引用运算符(不同于乘法运算符和全局引用运算符)。重载智能指针的`*`能使访问其持有的数据更为方便,在本章结束前谈到解引用强制多态时我们会说明方便的意义。
第八章的哈希 map 的“根据旧值更新一个值”部分简要的提到了解引用运算符。当时有一个可变引用,而我们希望改变这个引用所指向的值。为此,首先我们必须解引用。这是另一个使用`i32`值引用的例子:
@ -19,7 +19,7 @@ let mut x = 5;
assert_eq!(6, x);
```
我们使用`*y`来访问可变引用`y`所指向的数据,而是可变引用本身。接着可以修改它的数据,在这里对其加一。
我们使用`*y`来访问可变引用`y`所指向的数据,而是可变引用本身。接着可以修改它的数据,在这里对其加一。
引用并不是智能指针,他们只是引用指向的一个值,所以这个解引用操作是很直接的。智能指针还会储存指针或数据的元数据。当解引用一个智能指针时,我们只想要数据,而不需要元数据。我们希望能在使用常规引用的地方也能使用智能指针。为此,可以通过实现`Deref` trait 来重载`*`运算符的行为。
@ -69,7 +69,7 @@ struct that holds mp3 file data and metadata</span>
*(my_favorite_song.deref())
```
这个就是`self.audio`中的结果值。`deref`返回一个引用并接下来必需解引用而不是直接返回值的原因是所有权:如果`deref`方法直接返回值而不是引用,其值将被移动出`self`。这里和大部分使用解引用运算符的地方并不想获取`my_favorite_song.audio`的所有权。
这个就是`self.audio`中的结果值。`deref`返回一个引用并接下来必需解引用而不是直接返回值的原因是所有权:如果`deref`方法直接返回值而不是引用,其值将被移动出`self`。和大部分使用解引用运算符的地方相同,这里并不想获取`my_favorite_song.audio`的所有权。
注意将`*`替换为`deref`调用和`*`调用的过程在每次使用`*`的时候都会发生一次。`*`的替换并不会无限递归进行。最终的数据类型是`Vec<u8>`,它与列表 15-7 中`assert_eq!`的`vec![1, 2, 3]`相匹配。
@ -111,4 +111,4 @@ Rust 在发现类型和 trait 实现满足三种情况时会进行解引用强
头两个情况除了可变性之外是相同的:如果有一个`&T`,而`T`实现了返回`U`类型的`Deref`,可以直接得到`&U`。对于可变引用也是一样。最后一个有些微妙如果有一个可变引用它也可以强转为一个不可变引用。反之则是_不可能_的不可变引用永远也不能强转为可变引用。
`Deref` trait 对于能指针模式十分重要的原因在于智能指针可以被看作普通引用并用于期望使用引用的地方。例如,无需重新编写方法和函数来直接获取智能指针。
`Deref` trait 对于能指针模式十分重要的原因在于智能指针可以被看作普通引用并用于期望使用普通引用的地方。例如,无需重新编写方法和函数来直接获取智能指针。

@ -6,11 +6,11 @@
对于智能指针模式来说另一个重要的 trait 是`Drop`。`Drop`运行我们在值要离开作用域时执行一些代码。智能指针在被丢弃时会执行一些重要的清理工作,比如释放内存或减少引用计数。更一般的来讲,数据类型可以管理多于内存的资源,比如文件或网络连接,而使用`Drop`在代码处理完他们之后释放这些资源。我们在智能指针上下文中讨论`Drop`是因为其功能几乎总是用于实现智能指针。
在其他一些语言中,必须每次总是必须记住在使用完智能指针实例后调用清理内存或资源的代码。如果忘记的话,运行代码的系统可能会因为负荷过重而崩溃。在 Rust 中,可以指定一些代码应该在值离开作用域时被执行,而编译器会自动插入这些代码。这意味着无需记住在所有处理完这些类型实例后调用清理代码,而仍然不会泄露资源!
在其他一些语言中,我们不得不记住在每次使用完智能指针实例后调用清理内存或资源的代码。如果忘记的话,运行代码的系统可能会因为负荷过重而崩溃。在 Rust 中,可以指定一些代码应该在值离开作用域时被执行,而编译器会自动插入这些代码。这意味着无需记住在所有处理完这些类型实例后调用清理代码,而仍然不会泄露资源!
指定在值离开作用域时应该执行的代码的方式是实现`Drop` trait。`Drop` trait 要求我们实现一个叫做`drop`的方法,它获取一个`self`的可变引用。
列表 15-8 展示了并没有实际功能的结构体`CustomSmartPointer`,不过我们会在创建实例之后打印出`CustomSmartPointer created.`,而在实例离开作用域时打印出`Dropping CustomSmartPointer!`,这样就能看出哪些代码被执行了。不同于`println!`语句,我们在智能指针需要执行清理代码时使用`drop`
列表 15-8 展示了并没有实际功能的结构体`CustomSmartPointer`,不过我们会在创建实例之后打印出`CustomSmartPointer created.`,而在实例离开作用域时打印出`Dropping CustomSmartPointer!`,这样就能看出每一段代码是何时被执行的。实际的项目中,我们应该在`drop`中清理任何智能指针运行所需要的资源,而不是这个例子中的`println!`语句
<span class="filename">Filename: src/main.rs</span>
@ -36,7 +36,7 @@ fn main() {
implements the `Drop` trait, where we could put code that would clean up after
the `CustomSmartPointer`.</span>
`Drop` trait 位于 prelude 中,所以无需导入它。`drop`方法的实现调用了`println!`;这里是你需要实际需要放入关闭套接字代码的地方。在`main`函数中,我们创建一个`CustomSmartPointer`的新实例并打印出`CustomSmartPointer created.`以便在运行时知道代码运行到此。在`main`的结尾,`CustomSmartPointer`的实例会离开作用域。注意我们没有显式调用`drop`方法:
`Drop` trait 位于 prelude 中,所以无需导入它。`drop`方法的实现调用了`println!`;这里是你需要放入实际关闭套接字代码的地方。在`main`函数中,我们创建一个`CustomSmartPointer`的新实例并打印出`CustomSmartPointer created.`以便在运行时知道代码运行到此。在`main`的结尾,`CustomSmartPointer`的实例会离开作用域。注意我们没有显式调用`drop`方法:
当运行这个程序,我们会看到:

@ -62,7 +62,7 @@ error[E0382]: use of moved value: `a`
`Cons`成员拥有其储存的数据,所以当创建`b`列表时将`a`的所有权移动到了`b`。接着当再次尝使用`a`创建`c`时,这不被允许因为`a`的所有权已经被移动。
相反可以改变`Cons`的定义来存放一个引用,不过接着必须指定生命周期参数,而且也必须使列表的每一个元素都与列表本身存在的一样久那样构造列表的元素。否则借用检查器甚至都不会允许我们编译代码。
相反可以改变`Cons`的定义来存放一个引用,不过接着必须指定生命周期参数,而且在构造列表时,也必须使列表的每一个元素都至少与列表本身存在的一样久。否则借用检查器甚至都不会允许我们编译代码。
如列表 15-12 所示,可以将`List`的定义从`Box<T>`改为`Rc<T>`
@ -91,7 +91,7 @@ fn main() {
### 克隆`Rc<T>`会增加引用计数
之前我们见过`clone`方法,当时使用它来创建某些数据的完整拷贝。但是对于`Rc<T>`来说,它并不创建一个完整的拷贝。`Rc<T>`存放了**引用计数**,也就是说,一个存在多少个克隆的数量。让我们像列表 15-13 那样在创建`c`时增加一个内部作用域,并在不同的位置打印出关联函数`Rc::strong_count`的结果。`Rc::strong_count`返回传递给它的`Rc`值的引用计数,而在本章的稍后部分介绍避免引用循环时讲到它为什么叫做`strong_count`。
之前我们见过`clone`方法,当时使用它来创建某些数据的完整拷贝。但是对于`Rc<T>`来说,它并不创建一个完整的拷贝。`Rc<T>`存放了**引用计数**,也就是说,一个存在多少个克隆的计数器。让我们像列表 15-13 那样在创建`c`时增加一个内部作用域,并在不同的位置打印出关联函数`Rc::strong_count`的结果。`Rc::strong_count`返回传递给它的`Rc`值的引用计数,而在本章的稍后部分介绍避免引用循环时讲到它为什么叫做`strong_count`。
<span class="filename">Filename: src/main.rs</span>

Loading…
Cancel
Save