From dc101b8074951398f06f6cd9fd29d905fb08b5ec Mon Sep 17 00:00:00 2001 From: Unisko PENG Date: Thu, 27 Apr 2023 17:24:39 +0800 Subject: [PATCH] Improve Ch13 --- projects/FnMut_demo/Cargo.toml | 8 +++++++ projects/FnMut_demo/src/main.rs | 22 +++++++++++++++++++ ...anguage_Features_Iterators_and_Closures.md | 15 ++++++------- 3 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 projects/FnMut_demo/Cargo.toml create mode 100644 projects/FnMut_demo/src/main.rs diff --git a/projects/FnMut_demo/Cargo.toml b/projects/FnMut_demo/Cargo.toml new file mode 100644 index 0000000..65b97ba --- /dev/null +++ b/projects/FnMut_demo/Cargo.toml @@ -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] diff --git a/projects/FnMut_demo/src/main.rs b/projects/FnMut_demo/src/main.rs new file mode 100644 index 0000000..0c514f5 --- /dev/null +++ b/projects/FnMut_demo/src/main.rs @@ -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); +} diff --git a/src/Ch13_Functional_Language_Features_Iterators_and_Closures.md b/src/Ch13_Functional_Language_Features_Iterators_and_Closures.md index 6eac3fe..8b5882b 100644 --- a/src/Ch13_Functional_Language_Features_Iterators_and_Closures.md +++ b/src/Ch13_Functional_Language_Features_Iterators_and_Closures.md @@ -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)]