Merge pull request #908 from zxzxovo/main

fix typo and translation error
pull/911/head
KaiserY 2 days ago committed by GitHub
commit 9bf05de1df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -5,7 +5,7 @@
到本章的目前为止,我们大部分时间都专注于单个的 future 上。一个重要的例外就是我们用过的异步信道。回忆一下在本章之前的 [“消息传递”][17-02-messages] 中我们如何使用异步信道接收端的。异步 `recv` 方法随着时间的推移产生一个序列的项。这是一个更通用的模式的实例,通常被称为 *流**stream*)。
我们之前在第十三章的 [Iterator trait 和 `next` 方法][iterator-trait] 部分已经见过项的序列,不过迭代器和异步信道接收端有两个区别。第一个区别是时间维度:迭代器是同步的,而信道接收端是异步的。第二个区别是 API。当直接处理 `Iterator` 时,我们会调用其同步 `next` 方法。对于这个特定的 `trpl::Receiver` 流,我们调用一个异步的 `recv` 方法。除此之外,这两种 API 在使用上感觉十分相似,这种相似性并非巧合。流类似于一种异步形式的迭代器。然而, `trpl::Receiver` 专门等待接收消息,而通用的流 API 适用范围要广泛得多:它以与 `Iterator` 相同的方式一样提供下一个元素,但采用异步的方式。
我们之前在第十三章的 [Iterator trait 和 `next` 方法][iterator-trait] 部分已经见过项的序列,不过迭代器和异步信道接收端有两个区别。第一个区别是时间维度:迭代器是同步的,而信道接收端是异步的。第二个区别是 API。当直接处理 `Iterator` 时,我们会调用其同步 `next` 方法。对于这个特定的 `trpl::Receiver` 流,我们调用一个异步的 `recv` 方法。除此之外,这两种 API 在使用上感觉十分相似,这种相似性并非巧合。流类似于一种异步形式的迭代器。然而, `trpl::Receiver` 专门等待接收消息,而通用的流 API 适用范围要广泛得多:它以与 `Iterator` 相同的方式提供下一个元素,但采用异步的方式实现
Rust 中迭代器和流的相似性意味着我们实际上可以从任何迭代器上创建流。与迭代器类似,我们可以通过调用流的 `next` 方法并 await 其输出来使用它,如示例 17-30 所示。

@ -68,7 +68,7 @@ loop {
不过,如果 Rust 真的将代码精确地编译成那样,那么每一个 `await` 都会变成阻塞操作 -- 这恰恰与我们的目标相反相反Rust 确保循环可以将控制权交给一些可以暂停当前 future 转而去处理其它 future 并在之后再次检查当前 future 的内容。如你所见,这就是异步运行时,这种安排和协调的工作是其主要工作之一。
在本章前面的内容中,我们描述了等待 `rx.recv`。`recv` 调用返回一个 future并 await 轮询它的 future。我们注意到当信道关闭时运行时会暂停 future 直到它就绪并返回 `Some(message)``None` 为止。随着我们对 `Future` trait尤其是 `Future::poll` 的理解的深入,我们可以看出其是如何工作的。运行时知道 future 返回 `Poll::Pending` 时它还没有完成。反过来说,当 `poll` 返回 `Poll::Ready(Some(message))``Poll::Ready(None)` 时运行时知道 future **已经**完成了并继续运行
在本章前面的内容中,我们描述了等待 `rx.recv`。`recv` 调用返回一个 future并 await 轮询它的 future。我们注意到运行时会暂停 future 直到它就绪并返回 `Some(message)` 是信道关闭时返回 `None` 为止。随着我们对 `Future` trait尤其是 `Future::poll` 的理解的深入,我们可以看出其是如何工作的。当返回 `Poll::Pending` 时,运行时知道 future 还没有准备就绪。反过来说,当 `poll` 返回 `Poll::Ready(Some(message))``Poll::Ready(None)` 时运行时知道 future **已经** 准备就绪,并将其推进
运行时如何工作的具体细节超出了本书的范畴。不过关键在于理解 future 的基本机制:运行时**轮询**其所负责的每一个 future在它们还没有完成时使其休眠。
@ -129,7 +129,7 @@ pub trait Future {
我们会在 [第十八章][ch-18] 更多地看到这个语法。现在,知道如果要轮询一个 future 来检查它是 `Pending` 或者 `Ready(Output)`,我们需要一个 `Pin` 封装的该类型的可变引用就够了。
`Pin` 是一个类指针类型的封装,比如 `&``&mut``Box` 和 `Rc`。(从技术上来说,`Pin` 适用于实现了 `Deref``DerefMut` trait 的类型,不过这实际上等同于只能适用于指针。)`Pin` 本身并不是一个指针并且也不具备类似 `Rc``Arc` 那样引用技术的功能;它单纯地是一个编译器可以用来约束指针使用的工具。
`Pin` 是一个类指针类型的封装,比如 `&``&mut``Box` 和 `Rc`。(从技术上来说,`Pin` 适用于实现了 `Deref``DerefMut` trait 的类型,不过这实际上等同于只能适用于指针。)`Pin` 本身并不是一个指针并且也不具备类似 `Rc``Arc` 那样引用计数的功能;它单纯地是一个编译器可以用来约束指针使用的工具。
回忆一下 `await` 的实现是基于对 `poll` 的调用,这有助于解释之前见到的错误信息,不过那是关于 `Unpin` 的。所以 `Pin` 具体与 `Unpin` 有何关联,又为什么 `Future` 需要 `self` 在一个 `Pin` 类型中才能调用 `poll`
@ -181,7 +181,7 @@ pub trait Future {
然而,大多数类型即使被封装在 `Pin` 后面,也完全可以安全地移动。只有当项中含有内部引用的时候才需要考虑 pin。像数字或者布尔值这样的基本类型值是安全的因为很明显它们没有任何内部引用。大多数你在 Rust 中常用的类型也同样如此。例如你可以移动一个 `Vec` 而不用担心。考虑到目前我们所见到的,如果有一个 `Pin<Vec<String>>`,即便在没有其他引用的情况下 `Vec<String>` 始终可以安全移动,你仍然必须通过 `Pin` 提供的安全但有限的 API 来进行所有操作。我们需要一个方法来告诉编译器在类似这种情况下移动项是可以的 -- 这就是 `Unpin` 的用武之地了。
`Unpin` 是一个标记 traitmarker trait类似于我们在第十六章见过的 `Send``Sync` trait因此它们自身没有功能。标记 trait 的存在只是为了告诉编译器在给定上下文中可以安全地使用实现了给定 trait 的类型。`Unpin` 告知编译器这个给定类型**无需**维护被提及的值是否可以安全地移动的任何保证。
`Unpin` 是一个标记 traitmarker trait类似于我们在第十六章见过的 `Send``Sync` trait因此它们自身没有功能。标记 trait 的存在只是为了告诉编译器在给定上下文中可以安全地使用实现了给定 trait 的类型。`Unpin` 告知编译器这个给定类型**无需**对所涉及的值是否可以安全地移动做出任何保证。
正如 `Send``Sync` 一样,编译器自动为所有被证明为安全的类型实现 `Unpin`。同样类似于 `Send``Sync`,有一个特殊的例子**不会**为类型实现 `Unpin`。这个例子的符号是 <code>impl !Unpin for <em>SomeType</em></code>,这里 <code><em>SomeType</em></code> 指的是这样的一种类型:为了确保内存安全,当一个指向它的指针被用于 `Pin` 时,无论何时它都**必须**维护其不被移动的安全保证。

Loading…
Cancel
Save