mirror of
https://github.com/gnu4cn/rust-lang-zh_CN.git
synced 2025-01-30 06:00:13 +08:00
Improve Ch13
This commit is contained in:
parent
f54868603d
commit
864d704422
@ -959,31 +959,31 @@ pub fn search_insensitive<'a>(
|
||||
|
||||
**Choosing Between Loops or Iterators**
|
||||
|
||||
接着合乎逻辑的问题,便是在所编写代码中,应选取何种样式以及为什么要选择那种样式:是要清单 13-21 原先的实现,还是要清单 13-22 中用到迭代器的版本。绝大多数 Rust 程序员,都首选使用迭代器的样式。开始的时候要掌握这种诀窍有点难,不过一旦摸清各种迭代器适配器以及他们完成的事情,那么迭代器就能较容易地掌握。与其摆弄循环的各种东西,并构建出一些新的矢量值,运用迭代器的代码,关注的则是循环的高级别目标。那么运用迭代器就把一些常见代码,给抽象了出来,如此就更易于看出,特定于该代码的一些概念了,比如迭代器中的各个元素,所必须通过的那种过滤条件。
|
||||
下一个合乎逻辑的问题是,咱们应在自己的代码中选择哪种风格与为什么:清单 13-21 中原本的实现,或清单 13-22 中用到迭代器的版本。大多数 Rust 程序员喜欢使用迭代器风格。一开始他有点难掌握,但一旦咱们对各种迭代器适配器和他们的作用有了感觉,迭代器就会更容易理解。该代码没有拨弄循环的各个部分,与构建出新的矢量值,而是专注于循环的高级目标。这就把一些普通的代码抽象化了,所以更容易看到这段代码特有的概念,比如迭代器中每个元素必须通过的过滤条件。
|
||||
|
||||
然而这两种实现真的等价吗?直觉上的假定,可能是其中更低级别的循环,将会更快。那么下面就来讨论性能吧。
|
||||
但是,这两种实现方式真的等同吗?直观的假设可能是,更低级别的循环会更快。接下来咱们就会谈及性能问题。
|
||||
|
||||
|
||||
## 性能比较:循环与迭代器
|
||||
|
||||
**Comparing Performance: Loops vs. Iterators**
|
||||
|
||||
为确定出是要是要循环,还是使用迭代器,咱们需要搞清楚以下哪种实现更快:带有显式 `for` 循环的 `search` 函数,还是有着迭代器的那个版本。
|
||||
为确定是使用循环还是迭代器,咱们需要知道哪种实现更快:带有显式 `for` 循环的 `search` 函数版本,还带有迭代器的版本。
|
||||
|
||||
这里通过加载 Sir Arthur Conan Doyle 写的整部 *福尔摩斯历险记(The Adventures of Sherlock Holmes)* 到一个 `String` 中,并在这些内容里查找单词 *the*,运行了一个基准测试。下面就是这个基准测试,分别在使用 `for` 循环版本,与使用迭代器版本的 `search` 函数上的测试结果:
|
||||
我们通过将阿瑟-柯南-道尔爵士的《福尔摩斯历险记》的全部内容加载到一个字符串中,并在内容中寻找单词 "福尔摩斯",进行了一次基准测试。下面是使用 `for` 循环的 `search` 版本和使用迭代器的版本的基准测试结果:
|
||||
|
||||
```console
|
||||
test bench_search_for ... bench: 19,620,300 ns/iter (+/- 915,700)
|
||||
test bench_search_iter ... bench: 19,234,900 ns/iter (+/- 657,200)
|
||||
```
|
||||
|
||||
迭代器版本就要稍微快一些!由于这里关键不是要证实这两个版本等价,而是要对怎样从性能方面对两种实现加以比较,有个粗略认知,因此这里不会对这个基准测试代码加以解释(we won't explain the benchmark code here, because the point is not to prove that the two versions are equivalent but to get a general sense of how these two implementations compare performance-wise)。
|
||||
迭代器的版本稍微快了一些!由我们不会在这里解释基准代码,因为重点不是要证明这两个版本是等价的,而是要了解这两种实现在性能上的总体比较。
|
||||
|
||||
对于更为全面的基准测试,那么就应使用不同大小的各种文本作为其中的 `contents`,不同单词与不同长度单词作为那个 `query`,以及所有类别的其他差异。关键在于这里:尽管迭代器属于高级别的抽象,但他们会被向下编译为如同咱们自己所编写的低级别代码。迭代器是 Rust 的那些 *无代价抽象(zero-cost abstractions)* 之一,这就意味着这种抽象的使用,并不会承担额外的运行时开销。这与 C++ 最初设计者与实现者 Bjarne Stroustrup 在 “Foundation of C++”(2012) 那本书中,所定义的 *无开销(zero-overhead)* 概念类似:
|
||||
为了获得更全面的基准,你应该用各种大小的文本作为 `contents`,用不同的词和不同长度的词作为 `query`,以及其他各种变化来检查。重点是:迭代器虽然是个高级的抽象概念,但被编译成的代码与咱们自己编写的低级代码大致相同。迭代器是 Rust 的 *零成本抽象,zero-cost abstractions* 之一,我们的意思是使用该抽象不会带来额外的运行时开销。这类似于 C++ 最初的设计者和实现者 Bjarne Stroustrup 在《C++ 基础》(2012)中对零开销的定义:
|
||||
|
||||
> 总的来说,C++ 的众多实现,都遵循了无开销原则:用不到的东西,就无需付出代价。并更进了一步:即使用到,亦不会手搓出更良好的代码(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)。
|
||||
> 一般来说,C++ 的实现遵循零开销原则:咱们不使用的东西,咱们不需要付出开销。再进一步:咱们使用的东西,咱们不可能手写出更良好的代码,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。
|
||||
|
||||
作为另一个示例,以下代码取自某个音频解码器。其中的解码算法,使用了线性预测的数学运算,来根据先前的一些样本,估算出后面的值。此代码使用了迭代器链(an iterator chain),来完成作用域中三个变量:数据的一个 `buffer` 切片,12 个 `coeffecients` 的一个数组,及存储在 `qlp_shift` 中对数据进行偏移的数量,上的一些数学计算。这里已声明出了该示例中的那些变量,但并未给到他们任何值;尽管此代码在其上下文外部并无多少意义,但他仍不失为 Rust 如何将高级别的一些概念,翻译为低级别代码的一个简练的、真实世界下的示例。
|
||||
作为另一个示例,以下代码取自某个音频解码器。解码算法使用线性预测的数学运算,根据之前样本的线性函数来估计后面的数值。此代码使用迭代器链,an iterator chain=,对作用域中三个变量执行一些计算:由一些数据构成 `buffer` 切片,由 12 个 `coeffecients` 构成的一个数组,以及其中保存着数据偏移量的 `qlp_shift`。咱们已在这个示例中声明了变量,但并未给他们任何值;尽管此代码在其上下文之外没有什么意义,但他仍不失为说明 Rust 如何将高级别的概念,转化低级别代码的一个简练、真实的示例。
|
||||
|
||||
```rust
|
||||
let buffer: &mut [i32];
|
||||
|
@ -805,6 +805,10 @@ Consuming adaptor, `Iterator` 特质上,会调用到迭代器 `next` 方法的
|
||||
|
||||
Iterator adaptor,`Iterator` 特质上,通过改变原迭代器某些方面而产生出另一迭代器的一些方法。
|
||||
|
||||
- 零成本抽象
|
||||
|
||||
Zero-cost abstractions,相较于一般实现,语言提供的高级抽象在编译后生成的代码,与自己努力编写出的优化低级别代码类似。故使用高级抽象是没有运行时开销的。
|
||||
|
||||
- 文档注释
|
||||
|
||||
Documentation comment, 将产生出 HTML 的注释。
|
||||
|
Loading…
Reference in New Issue
Block a user