mirror of
https://github.com/gnu4cn/rust-lang-zh_CN.git
synced 2025-01-29 21:50:13 +08:00
Improve Ch13
This commit is contained in:
parent
c9782e2241
commit
dc101b8074
8
projects/FnMut_demo/Cargo.toml
Normal file
8
projects/FnMut_demo/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "FnMut_demo"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
22
projects/FnMut_demo/src/main.rs
Normal file
22
projects/FnMut_demo/src/main.rs
Normal file
@ -0,0 +1,22 @@
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut list = [
|
||||
Rectangle { width: 10, height: 1 },
|
||||
Rectangle { width: 3, height: 5 },
|
||||
Rectangle { width: 7, height: 12 },
|
||||
];
|
||||
|
||||
let mut sort_operations = vec! [];
|
||||
let value = String::from("按照被调用到的 key");
|
||||
|
||||
list.sort_by_key(|r| {
|
||||
sort_operations.push(&value);
|
||||
r.width
|
||||
});
|
||||
println! ("{:#?}\n{:#?}", list, sort_operations);
|
||||
}
|
@ -397,7 +397,7 @@ $ cargo run
|
||||
|
||||
`sort_by_key` 被定义为取 `FnMut` 闭包的原因是,他会多次调用闭包:对切片中的每个条目调用一次。闭包 `|r| r.width` 不会捕获、修改,或从其环境迁迁出任何东西,因此其满足特质边界要求。
|
||||
|
||||
作为对照,下面清单 13-8 给出一个仅实现了 `FnOnce` 特质的闭包示例,正是因为该闭包将值迁移出了其环境。编译器不会允许咱们在 `sort_by_key` 下使用这个闭包:
|
||||
相比之下,清单 13-8 展示了一个只实现 FnOnce 特质的闭包的例子,因为他会把值移出环境。编译器不会让咱们在 `sort_by_key` 下使用这个闭包:
|
||||
|
||||
文件名:`src/main.rs`
|
||||
|
||||
@ -426,9 +426,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
*清单 13-8:尝试在 `sort_by_key` 下使用某个 `FnOnce` 类型的闭包*
|
||||
*清单 13-8:尝试在 `sort_by_key` 下使用 `FnOnce` 类型的闭包*
|
||||
|
||||
这是一种人为杜撰的、错综复杂(而不会工作)的,来尝试计算 `sort_by_key` 在对 `list` 进行排序时,被调用次数的方法。此代码试图通过将该闭包所处环境中的 `value` -- 这样一个 `String`,压入到那个 `sort_operations` 矢量,而完成这样的计数。该闭包会捕获到 `value`,随后通过将 `value` 的所有权转移给 `sort_operations` 矢量,而将 `value` 迁移出这个闭包。这个闭包是可以调用一次的;由于 `value` 将不再位于那个其被再次压入到 `sort_operations` 的环境中,因此第二次的尝试调用他,就不会工作了。因此这个闭包就只实现了 `FnOnce`。在尝试编译此代码时,就会得到由于那个闭包必须实现 `FnMut`,因此 `value` 无法被迁移出那个闭包的错误:
|
||||
这是一个精心设计的、迂回的方法(并不奏效),试图计算排序列表时 `sort_by_key` 被调用的次数。这段代码尝试通过把 `value` -- 闭包环境中的一个 `String` -- 压入到 `sort_operations` 矢量,而完成这个计数。闭包会捕获 `value`,随后通过将 `value` 的所有权转移给 `sort_operations` 矢量,而把 `value` 迁出闭包。闭包可以被调用一次;由于 `value` 将不再位于其被再次压入到 `sort_operations` 的环境中,因此第二次尝试调用他将不会工作。那么,这个闭包就只实现了 `FnOnce`。在咱们尝试编译此代码时,就会得到由于闭包必须实现 `FnMut`,而因此 `value` 无法被迁出闭包的报错:
|
||||
|
||||
```console
|
||||
$ cargo run lennyp@vm-manjaro
|
||||
@ -448,7 +448,7 @@ For more information about this error, try `rustc --explain E0507`.
|
||||
error: could not compile `closure-example` due to previous error
|
||||
```
|
||||
|
||||
错误指向的是那个闭包函数体中,将 `value` 迁移出环境的那一行。为了修复这个问题,这里就需要对该闭包的函数体加以修改,从而令其不会将值迁移出环境。为对 `sort_by_key` 被调用次数加以计数,就要在环境中保留一个计数器,并在闭包函数体中增加该计数器的值,就是计算 `sort_by_key` 被调用次数的一种更为直接了当的方式。下面清单 13-9 中的闭包,由于其只捕获了到那个 `num_sort_operations` 计数器的可变引用,进而由此就可以被多次调用,那么这个闭包就会工作:
|
||||
报错指向的是闭包主体中,把 `value` 迁出环境的那行。要修复这个问题,咱们需要修改闭包的主体,令其不将值迁出环境。要计算sort_by_key被调用的次数,在环境中保留一个计数器并在闭包体中递增其值,是一种更直接的计算方法。下面清单 13-9 中的闭包,由于只捕获了到 `num_sort_operations` 计数器的可变引用,进而就可以被多次调用,其就会工作:
|
||||
|
||||
文件名:`src/main.rs`
|
||||
|
||||
@ -467,7 +467,6 @@ fn main() {
|
||||
];
|
||||
|
||||
let mut num_sort_operations = 0;
|
||||
|
||||
list.sort_by_key(|r| {
|
||||
num_sort_operations += 1;
|
||||
r.width
|
||||
@ -476,11 +475,11 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
*清单 13-9:在 `sort_by_key` 下使用一个 `FnMut` 闭包是允许的*
|
||||
*清单 13-9:在 `sort_by_key` 下使用 `FnMut` 闭包是允许的*
|
||||
|
||||
在定义那些运用到闭包的函数或类型时,这些 `Fn` 特质是相当重要的。在下一小节中,就会讨论到迭代器。许多迭代器的方法,都取的是闭包参数,因此请在继续学习时,牢记这些闭包的细节!
|
||||
在定义用到闭包的函数或类型时,这个 `Fn` 特质是相当重要的。下一小节中,咱们将讨论迭代器。许多迭代器方法,都会取闭包参数,因此在继续学习时,请牢记这些闭包的细节!
|
||||
|
||||
> **注**:将清单 13-8 的代码,只加入一个地址符号 `&`,而修改成下面这样,也是工作的。这就要想想是为什么了:)
|
||||
> 注:将清单 13-8 的代码,只加入一个地址符号 `&`,而修改成下面这样,也是工作的。这就要想想是为什么了:)
|
||||
|
||||
```rust
|
||||
#[derive(Debug)]
|
||||
|
Loading…
Reference in New Issue
Block a user