循环和迭代
- 循环: 是指在满足指定的条件的情况下, 重复的执行一段代码(需要满足指定条件才停止)
- 迭代: 是指对一个序列中的元素逐个访问的过程(元素全部被消费后会自动停止)
迭代器
迭代器模式: 对一系列项目执行某些任务 迭代器就负责遍历每一个项
Rust 的迭代器: Rust 迭代器是惰性的, 除非显示调用, 否则迭代器本身没有任何作用
Rust
fn main() {
let nums = vec![3, 2, 1];
let mut iter = nums.iter();
println!("iter: {:?}", iter); // 获取一个迭代器对象
// 手动一次次迭代
let item1 = iter.next(); // 手动调用 next 方法
println!("item1: {:?}", item1); // Some(3)
let item2 = iter.next();
println!("item2: {:?}", item2); // Some(2)
let item3 = iter.next();
println!("item3: {:?}", item3); // Some(1)
let item4 = iter.next();
println!("item3: {:?}", item4); // None
// 一次性全部遍历
for item in nums.iter() {
println!("item is: {:?}", item);
// 依次输出: 3 2 1
}
}
Iterator trait 和 next
所有迭代器都实现了 Iterator 特性, iterator trait 定义于标准库
rust
pub trait Iterator {
// 先不用管这个语法是什么意思,
// 只需要知道, 这个是 next 方法的返回值类型
type Item;
fn next(&mut self) -> Option<Self::Item>;
// ... 迭代器的其他方法 ... //
}
消费迭代器的方法
在 Iterator 中实现了很多方法, 其中在这些方法内部调用 next
方法的 就叫做 消费适配器(consuming adaptors)
被迭代器迭代的元素会有限的, 被消费已给就相当于吃掉
了一个
rust
fn main () {
let items = vec![1, 2, 3, 4, 5];
let iter = items.iter();
let x: i32 = iter.sum(); // 会获取迭代器的所有权
println!("sum = {}", x);
// 无法再次使用 迭代器, 因为所有权在 sum 方法那里
// for item in iter {
// println!("item = {}", item);
// }
// 这样是可以的, 因为这样是新创建了一个迭代器
// 和原来那个迭代器(iter) 没有关系
for item in items.iter() {
println!("item = {}", item);
}
}
迭代器适配器
所谓迭代器适配器(Iterator adaptors)
, 就是指可以将当前迭代器变为不同类型的迭代器, 可以链式调用多个迭代器, 但是 最后必须调用一个消费适配器方法
才能开始迭代, 因为所有的迭代器都是惰性的
rust
fn main () {
let items = vec![1, 2, 3, 4, 5];
let iter = items.iter();
println!(" iter: {:?}", iter);
let map_iter = iter.map(|x| x + 1);
// 可以看到 map_iter 并不是原来的 iter
// 而且,他仅仅是返回了一个新的迭代器
// 并没有执行出结果
println!("map_iter: {:?}", map_iter);
// 如果需要看到效果, 需要调用一个 消费适配器
// 如果不调用
let map_items: Vec<i32> = map_iter.collect();
// 输出: [2, 3, 4, 5, 6]
println!("map_items: {:?}", map_items);
}
自定义迭代器
要自定义迭代器就必须实现 Iterator 这个 trait
rust
#[derive(Debug)]
struct Stack<T> {
items: Vec<T>,
}
impl<T> Stack<T> {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn push(&mut self, item: T) {
self.items.push(item);
}
pub fn pop(&mut self) -> T {
self.items.pop().unwrap()
}
}
impl<T> Iterator for Stack<T> {
type Item = T;
// 只需要实现 next 方法即可
fn next(&mut self) -> Option<Self::Item> {
self.items.pop()
}
}
fn main () {
let mut stk = Stack::new();
stk.push(1);
stk.push(2);
stk.push(3);
for item in stk {
println!("item: {}", item); // 3,2,1
}
}
使用自定义迭代器上的其他方法
rust
fn main () {
let mut stk = Stack::new();
stk.push(1);
stk.push(2);
stk.push(3);
// items 需要指定类型
let items: Vec<i32> = stk.map(|x| x + 1).collect();
// 4,3,2
println!("{:?}", items);
}
迭代器和闭包的性能
迭代器是 Rust 的 零成本抽象(zero-cost abstractions)之一, 它意味着抽象并不会引入运行时开销
简单点来说就是: 虽然源码是这样写的, 但是最后还是会编译为循环, 所以不用担心性能问题
闭包和迭代器是 Rust 受函数式编程语言观念所启发的功能, 他们对 Rust 以底层的性能来明确的表达高级概念的能力有很大贡献, 闭包和迭代器的实现达到了不影响运行时性能的程度, 这正是 Rust 竭力提供零成本抽象的目标的一部分
这句话是Rust程序设计语言上的