昨天我们学了Iterator
迭代器
今天我们来用所学的知识优化下之前写的那个minigrep
还记得我们怎么把args
里的参数放到Config
实例中的吗?官方推荐的是clone
复制一份数据出来.而我这里用的则是生命周期.
其中的区别是可维护性和性能 。
我当时也是推荐的clone
,不过还是用生命周期来写,毕竟是在学习阶段.
扯远了,回到代码中.
env::args()
返回的是一个迭代器,那么我们完全可以从迭代器里获取数据.
来改下我们的lib.rs
中代码
然后再来改下main
函数
然后终端重新输入指令
可以看到使用迭代器我们省去了生命周期或者clone
方法.
这样既好维护又不会失去性能.
filter
我们是通过&str.contains
方法来判断是否存在匹配项的,其实lines
返回的也是一个迭代器,我们完全可以使用filter
顺便过滤了.
额,有点长了,因为我这里还需要把这个匹配到的数据传出去,所以多了一步map
转换类型以及获取所有权.
loop
)还是迭代(iterate
)在学迭代器之前,我们遍历都是通过for/while/loop
的方式,而学完迭代器之后我们又多了种遍历的方式.
那么loop
和iterate
之间哪个更快呢?
为了回答这个问题,rust
官方做了一个比较,在一本书*The Adventures of Sherlock Holmes*
[3]里找一个词,用找到这个词(所有,并不是找到一个就停止)所用的时间来判断.
可以明显看到迭代器所用的时间少很多.
迭代器是rust
中少有的*zero-cost abstractions
,*也就是零成本抽象概念,换句话说就是不会对runtime
有任何负担,在编译阶段就被转换成类似我们手动重复写的低级代码了
再来看个例子
这是一段音频解码器的解码算法,基于线性预测来计算,根据之前收集到的数据来线性预测将来的值.
这里有三个变量
coefficients
,它是一个数组, 有12
个元素buffer
,他也是一个数组,个数未知.qlp_shift
,是一个i16
类型的整数.三者做的运算
coefficients
和buffer
中第i-12..i
个进行zip
,什么是zip
呢?就像拉链一样
来看下zip
的例子,它返回一个新的迭代器,所以它是一个迭代器适配器.
然后我们来看下c
的数据
可以看到它返回的迭代器item
是一个元组包裹着两个迭代器里的item
.
然后将元组里的元素相乘,之后再把迭代器里的数据相加.
sum
方法前面说过了,就是将迭代器里的元素相加返回一个结果.
最后再向右偏移qlp_shift
个位置.
额,好像和我们的题目没啥关系?
其实还没说到点上,对于这样的代码,rust
在编译阶段不会去遍历,而是重复12
次,因为这里只有12
个元素,就像是我们去手写一样.
rust
开发团队称之为unrolls
.也就是展开.
通过两个小例子,rust
团队是想说: 尽情的用迭代器吧,不用害怕.
今天我们优化了下之前写的minigrep
小工具,然后又看了下迭代器和循环之间的区别,了解迭代器的部分底层相关知识.
发布于 2022-12-28 15:21・IP 属地广东