mirror of
https://github.com/KaiserY/trpl-zh-cn
synced 2024-11-09 00:43:59 +08:00
commit
a5fc515612
@ -79,7 +79,7 @@ commit 4f2dc564851dc04b271a2260c834643dfd86c724</p>
|
||||
<ul>
|
||||
<li><code>Box<T></code>,用于在堆上分配值</li>
|
||||
<li><code>Rc<T></code>,一个引用计数类型,其数据可以有多个所有者</li>
|
||||
<li><code>RefCell<T></code>,其本身并不是只能指针,不过它管理智能指针<code>Ref</code>和<code>RefMut</code>的访问,在运行时而不是在编译时执行借用规则。</li>
|
||||
<li><code>RefCell<T></code>,其本身并不是智能指针,不过它管理智能指针<code>Ref</code>和<code>RefMut</code>的访问,在运行时而不是在编译时执行借用规则。</li>
|
||||
</ul>
|
||||
<p>同时我们还将涉及:</p>
|
||||
<ul>
|
||||
@ -91,31 +91,31 @@ commit 4f2dc564851dc04b271a2260c834643dfd86c724</p>
|
||||
</div>
|
||||
|
||||
<!-- Mobile navigation buttons -->
|
||||
|
||||
|
||||
<a href="ch14-05-extending-cargo.html" class="mobile-nav-chapters previous">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="ch15-01-box.html" class="mobile-nav-chapters next">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a href="ch14-05-extending-cargo.html" class="nav-chapters previous" title="You can navigate through the chapters using the arrow keys">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="ch15-01-box.html" class="nav-chapters next" title="You can navigate through the chapters using the arrow keys">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@ -128,7 +128,7 @@ commit 4f2dc564851dc04b271a2260c834643dfd86c724</p>
|
||||
</script>
|
||||
|
||||
<!-- Livereload script (if served using the cli tool) -->
|
||||
|
||||
|
||||
|
||||
<script src="highlight.js"></script>
|
||||
<script src="book.js"></script>
|
||||
|
@ -147,36 +147,36 @@ struct that holds mp3 file data and metadata</span></p>
|
||||
<li>从<code>&mut T</code>到<code>&U</code>当<code>T: Deref<Target=U></code>。</li>
|
||||
</ul>
|
||||
<p>头两个情况除了可变性之外是相同的:如果有一个<code>&T</code>,而<code>T</code>实现了返回<code>U</code>类型的<code>Deref</code>,可以直接得到<code>&U</code>。对于可变引用也是一样。最后一个有些微妙:如果有一个可变引用,它也可以强转为一个不可变引用。反之则是_不可能_的:不可变引用永远也不能强转为可变引用。</p>
|
||||
<p><code>Deref</code> trait 对于只能指针模式十分重要的原因在于智能指针可以被看作普通引用并用于期望使用引用的地方。例如,无需重新编写方法和函数来直接获取智能指针。</p>
|
||||
<p><code>Deref</code> trait 对于智能指针模式十分重要的原因在于智能指针可以被看作普通引用并用于期望使用引用的地方。例如,无需重新编写方法和函数来直接获取智能指针。</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Mobile navigation buttons -->
|
||||
|
||||
|
||||
<a href="ch15-01-box.html" class="mobile-nav-chapters previous">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="ch15-03-drop.html" class="mobile-nav-chapters next">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a href="ch15-01-box.html" class="nav-chapters previous" title="You can navigate through the chapters using the arrow keys">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="ch15-03-drop.html" class="nav-chapters next" title="You can navigate through the chapters using the arrow keys">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@ -189,7 +189,7 @@ struct that holds mp3 file data and metadata</span></p>
|
||||
</script>
|
||||
|
||||
<!-- Livereload script (if served using the cli tool) -->
|
||||
|
||||
|
||||
|
||||
<script src="highlight.js"></script>
|
||||
<script src="book.js"></script>
|
||||
|
@ -8260,7 +8260,7 @@ commit 4f2dc564851dc04b271a2260c834643dfd86c724</p>
|
||||
<ul>
|
||||
<li><code>Box<T></code>,用于在堆上分配值</li>
|
||||
<li><code>Rc<T></code>,一个引用计数类型,其数据可以有多个所有者</li>
|
||||
<li><code>RefCell<T></code>,其本身并不是只能指针,不过它管理智能指针<code>Ref</code>和<code>RefMut</code>的访问,在运行时而不是在编译时执行借用规则。</li>
|
||||
<li><code>RefCell<T></code>,其本身并不是智能指针,不过它管理智能指针<code>Ref</code>和<code>RefMut</code>的访问,在运行时而不是在编译时执行借用规则。</li>
|
||||
</ul>
|
||||
<p>同时我们还将涉及:</p>
|
||||
<ul>
|
||||
@ -8446,7 +8446,7 @@ struct that holds mp3 file data and metadata</span></p>
|
||||
<li>从<code>&mut T</code>到<code>&U</code>当<code>T: Deref<Target=U></code>。</li>
|
||||
</ul>
|
||||
<p>头两个情况除了可变性之外是相同的:如果有一个<code>&T</code>,而<code>T</code>实现了返回<code>U</code>类型的<code>Deref</code>,可以直接得到<code>&U</code>。对于可变引用也是一样。最后一个有些微妙:如果有一个可变引用,它也可以强转为一个不可变引用。反之则是_不可能_的:不可变引用永远也不能强转为可变引用。</p>
|
||||
<p><code>Deref</code> trait 对于只能指针模式十分重要的原因在于智能指针可以被看作普通引用并用于期望使用引用的地方。例如,无需重新编写方法和函数来直接获取智能指针。</p>
|
||||
<p><code>Deref</code> trait 对于智能指针模式十分重要的原因在于智能指针可以被看作普通引用并用于期望使用引用的地方。例如,无需重新编写方法和函数来直接获取智能指针。</p>
|
||||
<a class="header" href="#drop-trait-运行清理代码" name="drop-trait-运行清理代码"><h2><code>Drop</code> Trait 运行清理代码</h2></a>
|
||||
<blockquote>
|
||||
<p><a href="https://github.com/rust-lang/book/blob/master/second-edition/src/ch15-03-drop.md">ch15-03-drop.md</a>
|
||||
@ -10035,15 +10035,15 @@ to know about. /Carol -->
|
||||
</div>
|
||||
|
||||
<!-- Mobile navigation buttons -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@ -10056,7 +10056,7 @@ to know about. /Carol -->
|
||||
</script>
|
||||
|
||||
<!-- Livereload script (if served using the cli tool) -->
|
||||
|
||||
|
||||
|
||||
<script src="highlight.js"></script>
|
||||
<script src="book.js"></script>
|
||||
|
@ -118,7 +118,7 @@ fn value_in_cents(coin: Coin) -> i32 {
|
||||
}
|
||||
```
|
||||
|
||||
如果调用`value_in_cents(Coin::Quarter(UsState::Alaska))`,`coin`将是`Coin::Quarter(UsState::Alaska)`。当将值与每个分支相比较时,没有分支会匹配知道遇到`Coin::Quarter(state)`。这时,`state`绑定的将会是值`UsState::Alaska`。接着就可以在`println!`表达式中使用这个绑定了,像这样就可以获取`Coin`枚举的`Quarter`成员中内部的州的值。
|
||||
如果调用`value_in_cents(Coin::Quarter(UsState::Alaska))`,`coin`将是`Coin::Quarter(UsState::Alaska)`。当将值与每个分支相比较时,没有分支会匹配直到遇到`Coin::Quarter(state)`。这时,`state`绑定的将会是值`UsState::Alaska`。接着就可以在`println!`表达式中使用这个绑定了,像这样就可以获取`Coin`枚举的`Quarter`成员中内部的州的值。
|
||||
|
||||
### 匹配`Option<T>`
|
||||
|
||||
|
@ -30,7 +30,7 @@ if let Some(3) = some_u8_value {
|
||||
|
||||
`if let`获取通过`=`分隔的一个模式和一个表达式。它的工作方式与`match`相同,这里的表达式对应`match`而模式则对应第一个分支。
|
||||
|
||||
使用`if let`意味着编写更少代码,更少的缩进和更少的样板代码。然而,这样会失去`match`强制要求的穷进行检查。`match`和`if let`之间的选择依赖特定的环境以及增加简洁度和失去穷尽性检查的权衡取舍。
|
||||
使用`if let`意味着编写更少代码,更少的缩进和更少的样板代码。然而,这样会失去`match`强制要求的穷尽性检查。`match`和`if let`之间的选择依赖特定的环境以及增加简洁度和失去穷尽性检查的权衡取舍。
|
||||
|
||||
换句话说,可以认为`if let`是`match`的一个语法糖,它当值匹配某一模式时执行代码而忽略所有其他值。
|
||||
|
||||
|
@ -237,7 +237,7 @@ character boundary', ../src/libcore/str/mod.rs:1694
|
||||
|
||||
幸运的是,这里还有其他获取字符串元素的方式。
|
||||
|
||||
如果你需要操作单独的 Unicode 标量值,最好的选择是使用`chars`方法。堆“नमस्ते”调用`chars`方法会将其分开并返回六个`char`类型的值,接着就可以遍历结果来访问每一个元素了:
|
||||
如果你需要操作单独的 Unicode 标量值,最好的选择是使用`chars`方法。对“नमस्ते”调用`chars`方法会将其分开并返回六个`char`类型的值,接着就可以遍历结果来访问每一个元素了:
|
||||
|
||||
```rust
|
||||
for c in "नमस्ते".chars() {
|
||||
|
@ -396,7 +396,7 @@ fn first_word<'a>(s: &'a str) -> &'a str {
|
||||
|
||||
这里我们提到一些 Rust 的历史是因为更多的明确的模式将被合并和添加到编译器中是完全可能的。未来将会需要越来越少的生命周期注解。
|
||||
|
||||
被编码进 Rust 引用分析的模式被称为**生命周期省略规则**(*lifetime elision rules*)。这并不是需要程序员遵守的规则;这些规则是一系列特定的场景,此时编译器会会考虑,如果代码符合这些场景,就不需要明确指定生命周期。
|
||||
被编码进 Rust 引用分析的模式被称为**生命周期省略规则**(*lifetime elision rules*)。这并不是需要程序员遵守的规则;这些规则是一系列特定的场景,此时编译器会考虑,如果代码符合这些场景,就不需要明确指定生命周期。
|
||||
|
||||
这些规则并不提供完整的推断:如果 Rust 在明确遵守这些规则的前提下变量的生命周期仍然是模棱两可的话,它不会猜测剩余引用的生命周期应该是什么。在这种情况,编译器会给出一个错误,这可以通过增加对应引用之间相联系的生命周期注解来解决。
|
||||
|
||||
|
@ -149,7 +149,7 @@ fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
|
||||
<!-- Will add wingdings in libreoffice /Carol -->
|
||||
|
||||
`lines`方法返回一个迭代器。第十三张会深入了解迭代器,不过我们已经在列表 3-6 中见过使用迭代器的方法,在那里使用了一个`for`循环和迭代器在一个集合的每一项上运行一些代码。
|
||||
`lines`方法返回一个迭代器。第十三章会深入了解迭代器,不过我们已经在列表 3-6 中见过使用迭代器的方法,在那里使用了一个`for`循环和迭代器在一个集合的每一项上运行一些代码。
|
||||
|
||||
<!-- so what does `lines` do on its own, if we need to use it in a for loop to
|
||||
work? -->
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
Rust 编译器执行的静态分析天生是保守的。代码的一些属性则不可能通过分析代码发现:其中最著名的就是停机问题(停机问题),这超出了本书的范畴,不过如果你感兴趣的话这是一个值得研究的有趣主题。
|
||||
|
||||
因为一些分析是不可能的,Rust 编译器在其不确定的时候甚至都不尝试猜测,所以说它是保守的而且有时会拒绝事实上不会违反 Rust 保证的正确的程序。换句话说,如果 Rust 接受不正确的程序,那么人们也就不会相信 Rust 所做的保证了。如果 Rust 拒绝正确的程序,会给程序员带来不变,但不会带来灾难。`RefCell<T>`正是用于当你知道代码遵守借用规则,而编译器不能理解的时候。
|
||||
因为一些分析是不可能的,Rust 编译器在其不确定的时候甚至都不尝试猜测,所以说它是保守的而且有时会拒绝事实上不会违反 Rust 保证的正确的程序。换句话说,如果 Rust 接受不正确的程序,那么人们也就不会相信 Rust 所做的保证了。如果 Rust 拒绝正确的程序,会给程序员带来不便,但不会带来灾难。`RefCell<T>`正是用于当你知道代码遵守借用规则,而编译器不能理解的时候。
|
||||
|
||||
类似于`Rc<T>`,`RefCell<T>`只能用于单线程场景。在并发章节会介绍如何在多线程程序中使用`RefCell<T>`的功能。现在所有你需要知道的就是如果尝试在多线程上下文中使用`RefCell<T>`,会得到一个编译错误。
|
||||
|
||||
|
@ -104,7 +104,7 @@ pointing to each other</span>
|
||||
|
||||
Rust 标准库中提供了`Weak<T>`,一个用于存在引用循环但只有一个方向有所有权的智能指针。我们已经展示过如何克隆`Rc<T>`来增加引用的`strong_count`;`Weak<T>`是一种引用`Rc<T>`但不增加`strong_count`的方式:相反它增加`Rc`引用的`weak_count`。当`Rc`离开作用域,其内部值会在`strong_count`为 0 的时候被丢弃,即便`weak_count`不为 0 。为了能够从`Weak<T>`中获取值,首先需要使用`upgrade`方法将其升级为`Option<Rc<T>>`。升级`Weak<T>`的结果在`Rc`还未被丢弃时是`Some`,而在`Rc`被丢弃时是`None`。因为`upgrade`返回一个`Option`,我们知道 Rust 会确保`Some`和`None`的情况都被处理并不会尝试使用一个无效的指针。
|
||||
|
||||
不同于列表 15-17 中每个项只知道它的下一项,加入我们需要一个树,它的项知道它的子项**和**父项。
|
||||
不同于列表 15-17 中每个项只知道它的下一项,假如我们需要一个树,它的项知道它的子项**和**父项。
|
||||
|
||||
让我们从一个叫做`Node`的存放拥有所有权的`i32`值和其子`Node`值的引用的结构体开始:
|
||||
|
||||
@ -276,4 +276,4 @@ examining strong and weak reference counts of `leaf` and `branch`</span>
|
||||
|
||||
[The Nomicon]: https://doc.rust-lang.org/stable/nomicon/vec.html
|
||||
|
||||
接下来,让我们谈谈 Rust 的并发。我们还会学习到一些新的堆并发有帮助的智能指针。
|
||||
接下来,让我们谈谈 Rust 的并发。我们还会学习到一些新的对并发有帮助的智能指针。
|
@ -4,14 +4,14 @@
|
||||
> <br>
|
||||
> commit da15de39eaabd50100d6fa662c653169254d9175
|
||||
|
||||
确保内存安全并不是 Rust 的唯一目标:作为一个能更好的处理并发和并行编程一直是 Rust 的另一个主要目标。
|
||||
确保内存安全并不是 Rust 的唯一目标:更好的处理并发和并行编程一直是 Rust 的另一个主要目标。
|
||||
**并发编程**(concurrent programming)代表程序的不同部分相互独立的执行,而**并行编程**代表程序不同部分同时执行,这两个概念在计算机拥有更多处理器可供程序利用时变得更加重要。由于历史的原因,在此类上下文中编程一直是困难且容易出错的:Rust 希望能改变这一点。
|
||||
|
||||
最开始,我们认为内存安全和防止并发问题是需要通过两个不同的方法解决的两个相互独立的挑战。然而,随着时间的推移,我们发现所有权和类型系统是一系列解决内存安全**和**并发问题的强用力的工具!通过改进所有权和类型检查,很多并发错误在 Rust 中都是**编译时**错误,而不是运行时错误。我们给 Rust 的这一部分起了一个绰号**无畏并发**(*fearless concurrency*)。无畏并发意味着 Rust 不光允许你自信代码不会出现诡异的错误,也让你可以轻易重构这种代码而无需担心会引入新的 bug。
|
||||
|
||||
> 注意:对于 Rust 的口号**无畏并发**,这里用**并发**指代很多问题而不是更精确的区分**并发和(或)并行**,是出于简化问题的原因。如果这是一本专注于并发和/或并行的书,我们肯定会更精确的。对于本章,当我们谈到**并发**时,请自行替换为**并发和(或)并行**。
|
||||
|
||||
很多语言所提供的处理并发问题的解决方法是非常有自身特色的。这是一个非常合理的策略,尤其是对于更高级的语言来说,不过对于底层语言来说可没有奢侈的选择。底层语言被期望为在任何给定的情况下,都可以使能提供最高性能的解决方案可行,同时他们对硬件有更少的抽象。因此,Rust 给了我们多种工具并以各种适合我们的情况和要求的方式来为问题建模。
|
||||
很多语言所提供的处理并发问题的解决方法都非常有特色,尤其是对于更高级的语言,这是一个非常合理的策略。然而对于底层语言则没有奢侈的选择。在任何给定的情况下,我们都期望底层语言可以提供最高的性能,并且对硬件有更薄的抽象。因此,Rust 给了我们多种工具,并以适合实际情况和需求的方式来为问题建模。
|
||||
|
||||
如下是本章将要涉及到的内容:
|
||||
|
||||
|
@ -222,7 +222,7 @@ fn main() {
|
||||
<span class="caption">Listing 16-4: A thread with a closure that attempts to
|
||||
capture a reference to `v` from a main thread that drops `v`</span>
|
||||
|
||||
这些代码可以运行,而新建线程则可能直接就出错了并完全没有机会运行。新建线程内部有一个`v`的引用,不过主线程仍在执行:它立刻丢弃了`v`,使用了第十五章提到的显式丢弃其参数的`drop`函数。接着,新建线程开始执行,现在`v`是无效的了,所以它的引用也就是无效得的。噢,这太糟了!
|
||||
这些代码可以运行,而新建线程则可能直接就出错了并完全没有机会运行。新建线程内部有一个`v`的引用,不过主线程仍在执行:它立刻丢弃了`v`,使用了第十五章提到的显式丢弃其参数的`drop`函数。接着,新建线程开始执行,现在`v`是无效的了,所以它的引用也就是无效的。噢,这太糟了!
|
||||
|
||||
为了修复这个问题,我们可以听取错误信息的建议:
|
||||
|
||||
|
@ -52,7 +52,7 @@ single threaded context for simplicity</span>
|
||||
|
||||
与很多类型一样,我们通过叫做`new`的关联函数来创建一个`Mutex<T>`。为了访问互斥器中的数据,使用`lock`方法来获取锁。这个调用会阻塞到直到轮到我们拥有锁为止。如果另一个线程拥有锁接着那个线程 panic 了则这个调用会失败。类似于上一部分列表 16-6 那样,我们暂时使用`unwrap()`,至于更好的错误处理,请查看第九章中提供的更好的工具。
|
||||
|
||||
一旦获取了锁,就可以将返回值(在这里是`num`)作为一个数据的可变引用使用了。类型系统是 Rust 如何保证使用值之前必须获取锁的:`Mutex<i32>`并不是一个`i32`,所以**必须**获取锁才能使用这个`i32`值。我们是不会忘记这么做的;因为类型系统是不会允许的。
|
||||
一旦获取了锁,就可以将返回值(在这里是`num`)作为一个数据的可变引用使用了。观察 Rust 类型系统如何保证使用值之前必须获取锁:`Mutex<i32>`并不是一个`i32`,所以**必须**获取锁才能使用这个`i32`值。我们是不会忘记这么做的,因为类型系统不允许。
|
||||
|
||||
与你可能怀疑的一样,`Mutex<T>`是一个智能指针。好吧,更准确的说,`lock`调用返回一个叫做`MutexGuard`的智能指针。类似我们在第十五章见过的智能指针,它实现了`Deref`来指向其内部数据。另外`MutexGuard`有一个用来释放锁的`Drop`实现。这样就不会忘记释放锁了。这在`MutexGuard`离开作用域时会自动发生,例如它发生于列表 16-12 中内部作用域的结尾。接着可以打印出互斥器的值并发现能够将其内部的`i32`改为 6。
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user