13.5.0. 写在正文之前
Rust语言在设计过程中收到了很多语言的启发,而函数式编程对Rust产生了非常显著的影响。函数式编程通常包括通过将函数作为值传递给参数、从其他函数返回它们、将它们分配给变量以供以后执行等等。
在本章中,我们会讨论 Rust 的一些特性,这些特性与许多语言中通常称为函数式的特性相似:
- 闭包
- 迭代器(本文)
- 使用闭包和迭代器改进I/O项目
- 闭包和迭代器的性能
喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
13.5.1. 什么是迭代器
提到迭代器,就得先讲迭代器模式。迭代器模式允许你依次对一系列项里的每一个元素执行某些任务。 而在这个过程中,迭代器负责:
- 遍历每个项
- 确定序列(的遍历)何时完成
Rust的迭代器是懒惰的(lazy):除非调用消费迭代器的方法,否则迭代器本身没有任何效果。这句话的意思大致是如果你在代码里写了迭代器但没有用到,那么迭代器就相当于什么都没干。
看个例子:
fn main() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
}
v1
是一个Vector
,v1.iter()
就是在给v1
产生了一个迭代器,赋给了v1_iter
,但是目前v1_iter
没有被使用,所以迭代器可以被看作没有任何效果。
那我们使用迭代器来遍历:
fn main() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
for val in v1_iter {
println!("Got: {}", val);
}
}
这就相当于迭代器里的每个元素都被用在了一次循环里。
13.5.2. Iterator trait
所有的迭代器都实现了Iterator
trait。这个trait定义在标准库之下,定义大致如下:
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// methods with default implementations elided
}
这里面涉及两个新语法:type item
和Self::Item
,这两个语法定义了与这个trait关联的类型,这部分放在以后的文章讲。现在你需要知道的就是实现Iterator
trait需要你定义一个Item
类型,它用于next
方法的返回类型(迭代器的返回类型)。
iterator
这个trait仅要求实现一个方法——next
。next
方法每次调用迭代器它都会返回迭代器中的一项,也就是迭代器中的一个元素,而由于返回类型是Option
,所以返回的结果会被包裹在Option
下的Some
变体里。如果迭代结束,就会返回Option
下的None
。
实际使用时可以直接在迭代器上调用next
方法,看个例子:
#[cfg(test)]
mod tests {
#[test]
fn iterator_demonstration() {
let v1 = vec![1, 2, 3];
let mut v1_iter = v1.iter();
assert_eq!(v1_iter.next(), Some(&1));
assert_eq!(v1_iter.next(), Some(&2));
assert_eq!(v1_iter.next(), Some(&3));
assert_eq!(v1_iter.next(), None);
}
}
v1
是一个Vector
,v1_iter
是v1
的迭代器,由于下面的操作会被视为修改迭代器内容所以得加mut
关键字声明为可用。assert_eq!(v1_iter.next(), Some(&1));
这句话是第一次调用next
,就会返回Vector
里第一个元素,用Some
包裹,也就是Some(&1)
,这里是&1
是因为迭代器的返回值是被Option
类型包裹的不可变引用。assert_eq!(v1_iter.next(), Some(&2));
是第二次调用next
,就会返回Vector
里第二个元素,用Some
包裹,也就是Some(&2)
- 以此类推…
- 在迭代器上调用
next
方法会更改迭代器用于跟踪其在序列中位置的内部状态。换句话说,每一次调用就是消耗了这个迭代器里一个元素。而13.5.1中例子的for
循环不需要mut
是因为for
循环实际上取得了v1_iter
的所有权。
13.5.3. 几种迭代方法
刚才使用的 iter
方法生成的是一个不可变引用的迭代器,通过next
方法所取得的值实际上是指向Vector
中的元素的不可变引用。
into_iter
方法创建的迭代器会获得所有权。也就是它在迭代元素时会把元素移动到新的作用域内,并取得所有权。
iter_mut
方法在遍历函数时使用的是可变的引用。