Update Ch20

This commit is contained in:
Unisko PENG 2023-04-03 18:03:00 +08:00
parent 8abbe904eb
commit 249c96626b
3 changed files with 51 additions and 14 deletions

View File

@ -5,4 +5,11 @@ impl ThreadPool {
pub fn new(size: usize) -> ThreadPool {
ThreadPool
}
pub fn execute<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
}
}

View File

@ -75,7 +75,7 @@ fn main() {
let user_pref1 = Some(ShirtColor::Red);
let giveaway1 = store.giveaway(user_pref1);
println! (
"选项为 {:?} 的用户,得到了 {:?}",
"选项为 {:?} 的用户,得到了 {:?}",
user_pref1, giveaway1
);
@ -138,9 +138,9 @@ let expensive_closure = |num: u32| -> u32 {
```rust
fn add_one_v1 (x: u32) -> u32 { x + 1 };
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x| { x + 1 };
let add_one_v4 = |x| x + 1 ;
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x| { x + 1 };
let add_one_v4 = |x| x + 1 ;
```
第一行给出了一个函数定义,而第二行则给出的是一个完整注解过的闭包定义。在第三行中,这里移除了那个闭包定义的类型注解。在第四行,就移出了那对花括号,由于这个闭包的函数体只有一个表达式,因此这对花括号是可选的。这些全都是有效的定义,在他们被调用时,都会产生出同样的行为。由于 `add_one_v3``add_one_v4` 中的那些类型将从他们的用法中推断出来,因此这两个行就需要被执行的闭包,能够被编译。这一点与 `let v = Vec::new();` 要么需要类型注解,或是需要有某种类型的值插入到这个 `Vec`Rust 才能够推断出他的类型类相似。
@ -281,7 +281,7 @@ fn main() {
这里生成了一个新线程将一个闭包作为参数给到这个线程来运行we spawn a new thread, giving the thread a closure to run as an argument。其中闭包的函数体打印出这个清单。在代码清单 13-4 中,由于不可变引用是打印那里清单所需的最少量权限,因此那里的闭包只使用了不可变引用对 `list` 加以了捕获。而在这个示例中,即使其中的闭包函数体只需要不可变引用,这里仍需要通过把那个 `move` 关键字放置于闭包定义的开头,指明那个 `list` 应被迁移到该闭包中。这个新线程可能在主线程其余部分执行完毕之前就执行结束,或主线程可能先结束。若主线程仍保有 `list` 的所有权,而在新线程结束之前就结束,而丢弃掉 `list`,那么在那个线程中的 `list` 就会成为无效。因此,编译器就要求其中的 `list` ,被迁移到那个给到新线程的闭包中,如此那个引用就将有效。请尝试去掉这个 `move` 关键字,或在那个闭包被之后使用 `list`,来看看会得到什么编译器错误!
### 将捕获到的值迁移出闭包与 `Fn` 特质
### <a id="moving-captured-values-out-of-closures-and-the-Fn-traits"></a>将捕获到的值迁移出闭包与 `Fn` 特质
**Moving Captured Values Out of Closures and the `Fn` Traits**
@ -759,8 +759,8 @@ impl Config {
let ignore_case = env::var("IGNORE_CASE").is_ok();
Ok(Config {
query,
Ok(Config {
query,
file_path,
ignore_case,
})
@ -794,7 +794,7 @@ fn main() {
eprintln! ("解析参数时遇到问题:{err}");
process::exit(1);
});
// --跳过代码--
}
```
@ -866,8 +866,8 @@ impl Config {
let ignore_case = env::var("IGNORE_CASE").is_ok();
Ok(Config {
query,
Ok(Config {
query,
file_path,
ignore_case,
})
@ -890,7 +890,7 @@ impl Config {
```rust
pub fn search<'a>(
query: &str,
query: &str,
contents: &'a str
) -> Vec<&'a str> {
let mut results = Vec::new();
@ -913,7 +913,7 @@ pub fn search<'a>(
```rust
pub fn search<'a>(
query: &str,
query: &str,
contents: &'a str
) -> Vec<&'a str> {
contents
@ -932,7 +932,7 @@ pub fn search<'a>(
```rust
pub fn search_insensitive<'a>(
query: &str,
query: &str,
contents: &'a str
) -> Vec<&'a str> {
let query = query.to_lowercase();

View File

@ -682,4 +682,34 @@ For more information about this error, try `rustc --explain E0599`.
error: could not compile `hello` due to previous error
```
现在的报错之所以出现,是因为在 `ThreadPool` 上咱们没有一个 `execute` 方法。回顾 ["创建有限数目的线程"](#creating-a-finite-number-of-threads) 小节到,咱们已决定咱们的线程池,应有一个类似与 `thread::spawn` 的接口。此外,
现在的报错之所以出现,是因为在 `ThreadPool` 上咱们没有一个 `execute` 方法。回顾 ["创建有限数目的线程"](#creating-a-finite-number-of-threads) 小节到,咱们已决定咱们的线程池,应有一个类似与 `thread::spawn` 的接口。此外,咱们将实现这个 `execute` 函数,如此其便会取那个给到他的闭包,并将其交给线程池中的某个空闲进程运行。
咱们将在 `ThreadPool` 上定义这个 `execute` 方法,来取一个闭包作为参数。回顾第 13 章中 [“将捕获值迁移出闭包与 `Fn` 特质”](Ch13_Functional_Language_Features_Iterators_and_Closures.md#moving-captured-values-out-of-closures-and-the-Fn-traits) 到咱们可以三种不同特质,将闭包取作参数:`Fn`、`FnMut` 与 `FnOnce`。咱们需要确定出这里要使用何种类别的闭包。咱们清楚咱们将以完成一些类似于标准库的 `thread::spawn` 实现类似的东西结束,因此咱们就可以看看 `thread::spawn` 的签名在其参数上有些什么。文档给出咱们下面的东西:
```rust
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
```
其中的 `F` 类型参数,就是咱们在这里所关心的那个;那个 `T` 类型参数于返回值相关,而咱们并不关心那个。咱们可以看出,`spawn` 使用 `FnOnce` 作为 `F` 上的特质边界。由于咱们将最终将把咱们在 `execute` 中获得的实参,传递给 `spawn`,因此这或许也正是咱们想要的。由于为运行某个请求的线程,将只执行那个请求的闭包一次,而这是与 `FnOnce` 中的 `Once` 是相匹配的,故咱们可以进一步确信,`FnOnce` 便是咱们要用到的特质。
其中的 `F` 类型参数,还有着特质边界 `Send` 与生命周期边界 `'static`,在咱们这种情况下他们是有用的:咱们需要 `Send` 来将闭包,从一个线程转移到另一线程,并由于咱们不知道那个线程将耗时多久来执行,因此而需要 `'static`。下面咱们就来在 `ThreadPool` 上,创建出将取到有着这些边界的,类型 `F` 的泛型参数的 `execute` 方法:
文件名:`src/lib.rs`
```rust
#![allow(warnings)]
pub struct ThreadPool;
impl ThreadPool {
pub fn execute<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
}
}
```