diff --git a/src/ch13-01-closures.md b/src/ch13-01-closures.md index de35641..303ab29 100644 --- a/src/ch13-01-closures.md +++ b/src/ch13-01-closures.md @@ -72,7 +72,7 @@ let add_one_v3 = |x| { x + 1 }; // a closure eliding types let add_one_v4 = |x| x + 1 ; // without braces ``` -定义闭包时并要求类型注解而在定义函数是要求的原因在于函数是显式暴露给用户的接口的一部分,所以为了严格的定义接口确保所有人都同意函数使用和返回的值类型是很重要的。但是闭包并不像函数那样用于暴露接口:他们存在于绑定中并直接被调用。强制标注类型就等于为了很小的优点而显著的降低了工程性(本末倒置)。 +定义闭包时不要求类型注解而在定义函数时要求的原因在于函数是显式暴露给用户的接口的一部分,所以为了严格的定义接口确保所有人都同意函数使用和返回的值类型是很重要的。但是闭包并不像函数那样用于暴露接口:他们存在于绑定中并直接被调用。强制标注类型就等于为了很小的优点而显著的降低了工程性(本末倒置)。 不过闭包的定义确实会推断每一个参数和返回值的类型。例如,如果用`i8`调用列表 13-1 中没有类型注解的闭包,如果接着用`i32`调用同一闭包则会得到一个错误: diff --git a/src/ch13-02-iterators.md b/src/ch13-02-iterators.md index 5d643b3..83aab4d 100644 --- a/src/ch13-02-iterators.md +++ b/src/ch13-02-iterators.md @@ -27,7 +27,7 @@ vector 的`iter`方法允许从 vector 创建一个**迭代器**(*iterator*) 1. 从 vector 中创建了一个迭代器。 2. 使用`map`适配器和一个闭包参数对每一个元素加一。 -3. 使用`collect`适配器来消费迭代去并生成了一个新的 vector。 +3. 使用`collect`适配器来消费迭代器并生成了一个新的 vector。 这就是如何产生结果`[2, 3, 4]`的。如你所见,闭包是使用迭代器的很重要的一部分:他们提供了一个自定义类似`map`这样的迭代器适配器的行为的方法。 @@ -52,7 +52,7 @@ nothing unless consumed, #[warn(unused_must_use)] on by default | ^^^^^^^^^^^^^^^^^^^^^^^^^ ``` -这个警告是因为迭代器适配器实际上并不自己进行处理。他们需要一些其他方法来触发迭代器链的计算。我们称之为**消费迭代器**(*consuming adaptors*),而`collect`就是其中之一。 +这个警告是因为迭代器适配器实际上并不自己进行处理。他们需要一些其他方法来触发迭代器链的计算。我们称之为**消费适配器**(*consuming adaptors*),而`collect`就是其中之一。 那么如何知道迭代器方法是否消费了迭代器呢?还有哪些适配器是可用的呢?为此,让我们看看`Iterator` trait。 @@ -68,7 +68,7 @@ trait Iterator { } ``` -这里有一些还未讲到的新语法:`type Item`和`Self::Item`定义了这个 trait 的**关联类型**(*associated type*),第XX章会讲到关联类型。现在所有你需要知道就是这些代码表示`Iterator` trait 要求你也定义一个`Item`类型,而这个`Item`类型用作`next`方法的返回值。换句话说,`Item`类型将是迭代器返回的元素的类型。 +这里有一些还未讲到的新语法:`type Item`和`Self::Item`定义了这个 trait 的**关联类型**(*associated type*),第19章会讲到关联类型。现在所有你需要知道就是这些代码表示`Iterator` trait 要求你也定义一个`Item`类型,而这个`Item`类型用作`next`方法的返回值。换句话说,`Item`类型将是迭代器返回的元素的类型。 让我们使用`Iterator` trait 来创建一个从一数到五的迭代器`Counter`。首先,需要创建一个结构体来存放迭代器的当前状态,它有一个`u32`的字段`count`。我们也定义了一个`new`方法,当然这并不是必须的。因为我们希望`Counter`能从一数到五,所以它总是从零开始: diff --git a/src/ch13-04-performance.md b/src/ch13-04-performance.md index 5a04dc5..d95426a 100644 --- a/src/ch13-04-performance.md +++ b/src/ch13-04-performance.md @@ -11,7 +11,7 @@ test bench_grep_for ... bench: 19,620,300 ns/iter (+/- 915,700) test bench_grep_iter ... bench: 19,234,900 ns/iter (+/- 657,200) ``` -结果迭代器版本还要稍微快一点!这里我们将不会查看性能测试的代码,光是这一点并不是为了证明他们是完全等同的,而是提供了一个大体上比较这两种实现的方向。对于**真正**的性能测试,将会检查不同长度的文本、不同的搜索单词、不同长度的单词和所有其他的可变情况。这里所要表达的是:迭代器,作为一个高级的抽象,被编译成了与手写的底层代码大体一致性能代码。迭代器是 Rust 的**零成本抽象**(*zero-cost abstractions*)之一,它意味着抽象并不会强加运行时开销,它与本贾尼·斯特劳斯特卢普,C++ 的设计和实现者所定义的**零开销**(*zero-overhead*)如出一辙: +结果迭代器版本还要稍微快一点!这里我们将不会查看性能测试的代码,我们的目的并不是为了证明他们是完全等同的,而是得出一个怎样比较这两种实现方式的基本思路。对于**真正**的性能测试,将会检查不同长度的文本、不同的搜索单词、不同长度的单词和所有其他的可变情况。这里所要表达的是:迭代器,作为一个高级的抽象,被编译成了与手写的底层代码大体一致性能代码。迭代器是 Rust 的**零成本抽象**(*zero-cost abstractions*)之一,它意味着抽象并不会强加运行时开销,它与本贾尼·斯特劳斯特卢普,C++ 的设计和实现者所定义的**零开销**(*zero-overhead*)如出一辙: > In general, C++ implementations obey the zero-overhead principle: What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better. > @@ -21,7 +21,7 @@ test bench_grep_iter ... bench: 19,234,900 ns/iter (+/- 657,200) > > - 本贾尼·斯特劳斯特卢普 "Foundations of C++" -作为另一个例子,这里有一些来自于音频解码器的代码。这些代码使用迭代器链来对作用域中的三个变量进行了某种数学计算:一个叫`buffer`的数据 slice、一个 12 个系数列表的`coefficients`、和一个移位位数的`qlp_shift`。例子中声明了这些变量但并没有提供任何值;虽然这些代码在其上下文之外没有什么意义,不过仍是一个简洁的现实中的例子,来展示 Rust 如何将高级概念转换为底层代码: +作为另一个例子,这里有一些来自于音频解码器的代码。这些代码使用迭代器链来对作用域中的三个变量进行了某种数学计算:一个叫`buffer`的数据 slice、一个有12个元素的数组`coefficients`、和一个代表移位位数的`qlp_shift`。例子中声明了这些变量但并没有提供任何值;虽然这些代码在其上下文之外没有什么意义,不过仍是一个简洁的现实中的例子,来展示 Rust 如何将高级概念转换为底层代码: ```rust,ignore let buffer: &mut [i32];