Rust 迭代器
Rust 中的迭代器是一种方便、高效的数据遍历方法,它提供了一种抽象的方式来访问集合中的每个元素,而不需要显式地管理索引或循环。
迭代器允许你以一种声明式的方式来遍历序列,如数组、切片、链表等集合类型的元素。
迭代器背后的核心思想是将数据处理过程与数据本身分离,使代码更清晰、更易读、更易维护。
迭代器遵循以下原则:
-
惰性求值:迭代器不会立即计算其元素,而是在需要时才计算,这使得迭代器可以用于处理无限序列。例如,当调用 map() 或 filter() 方法时,并不会立即对集合进行转换或过滤,而是返回一个新的迭代器,只有当真正需要获取数据时,才会对数据进行转换或过滤。
-
消费性:在迭代器完成迭代后,它所迭代的集合将被消费,即集合的所有权被转移给迭代器,集合不能再被使用。
-
不可变访问:迭代器默认以不可变方式访问其元素,这意味着在迭代过程中不能修改元素。
-
所有权:迭代器可以处理拥有或借用的元素。当迭代器借用元素时,它不会取得元素的所有权。例如,iter() 方法返回的是一个借用迭代器,而 into_iter() 方法返回的是一个获取所有权的迭代器。
创建迭代器
使用 iter() 方法创建借用迭代器:
let vec = vec![1, 2, 3, 4, 5]; let iter = vec.iter();
使用 iter_mut() 方法创建可变借用迭代器:
let mut vec = vec![1, 2, 3, 4, 5]; let iter_mut = vec.iter_mut();
使用 into_iter() 方法创建获取所有权的迭代器:
let vec = vec![1, 2, 3, 4, 5]; let into_iter = vec.into_iter();
迭代器方法
Rust 的迭代器提供了丰富的方法来处理集合中的元素,其中一些常见的方法包括:
-
map()
:对每个元素应用给定的转换函数。 -
filter()
:根据给定的条件过滤集合中的元素。 -
fold()
:对集合中的元素进行累积处理。 -
skip()
:跳过指定数量的元素。 -
take()
:获取指定数量的元素。 -
enumerate()
:为每个元素提供索引。 - ……
使用 map() 方法对每个元素进行转换:
let vec = vec![1, 2, 3, 4, 5]; let squared_vec: Vec = vec.iter().map(|x| x * x).collect();
使用 filter() 方法根据条件过滤元素:
let vec = vec![1, 2, 3, 4, 5]; let filtered_vec: Vec = vec.into_iter().filter(|&x| x % 2 == 0).collect();
使用 for 循环遍历迭代器
Rust 提供了 for 循环语法来遍历迭代器中的元素,是一种更加简洁和直观的遍历方式。
Rust 的 for 循环底层实际上是使用迭代器的。
let vec = vec![1, 2, 3, 4, 5]; for &num in vec.iter() { println!("{}", num); }
在这个循环中,vec.iter() 返回一个迭代器,for 循环遍历这个迭代器,并将每个元素赋值给 num 变量,然后执行循环体中的代码。
消费迭代器
使用迭代器直到它被完全消耗。
实例
let mut iter = arr.into_iter();
while let Some(val) = iter.next() {
println!(“{}”, val);
}
适配器
迭代器适配器是一系列提供给迭代器的函数,它们可以修改迭代器的行为。例如 map, filter, take 等。
let arr = [1, 2, 3, 4, 5]; let even_numbers: Vec = arr.into_iter().filter(|&x| x % 2 == 0).collect();
迭代器链
可以将多个迭代器适配器链接在一起,形成迭代器链。
实例
let arr = [1, 2, 3, 4, 5];
let mut iter = arr.into_iter().peekable();
while let Some(val) = iter.next() {
if val % 2 == 0 {
continue;
}
println!(“{}”, val);
}
收集器
使用 collect 方法将迭代器的元素收集到某种集合中。
let arr = [1, 2, 3, 4, 5]; let sum: i32 = arr.into_iter().sum();
迭代器和生命周期
迭代器的生命周期与它所迭代的元素的生命周期相关联。迭代器可以借用元素,也可以取得元素的所有权。这在迭代器的实现中通过生命周期参数来控制。
迭代器与闭包
迭代器适配器经常与闭包一起使用,闭包允许你为迭代器操作提供定制逻辑。
迭代器和性能
迭代器通常是非常高效的,因为它们允许编译器做出优化。例如,编译器可以内联迭代器适配器的调用,并且可以利用迭代器的惰性求值特性。
实例
下面实例演示了如何使用迭代器对一个数组进行遍历,并输出数组中的元素。
实例
fn main() {
// 定义一个包含整数的数组
let numbers = vec![1, 2, 3, 4, 5];
// 使用迭代器对数组进行遍历,并输出每个元素
println!(“Iterating through the array:”);
for num in numbers.iter() {
println!(“{}”, num);
}
// 使用迭代器的 map 方法对数组中的每个元素进行平方运算,并收集结果到一个新的数组中
let squared_numbers: Veci32> = numbers.iter().map(|x| x * x).collect();
// 输出平方后的数组
println!(“Squared numbers: {:?}”, squared_numbers);
}
以上代码中,我们首先定义了一个包含整数的数组 numbers
,然后使用 iter()
方法获取数组的迭代器,并通过 for
循环遍历迭代器,输出数组中的每个元素。接着使用迭代器的 map()
方法对数组中的每个元素进行平方运算,并使用 collect()
方法将结果收集到一个新的数组 squared_numbers
中。最后输出了平方后的数组。
运行该程序,可以看到输出了原始数组中的每个元素,以及经过平方运算后的新数组:
Iterating through the array: 1 2 3 4 5 Squared numbers: [1, 4, 9, 16, 25]
这个例子演示了 Rust 中迭代器的基本用法,包括遍历、转换和收集结果。
以下实例使用 filter() 方法对一个数组进行过滤,并输出过滤后的结果:
实例
fn main() {
// 定义一个包含整数的数组
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 使用迭代器的 filter 方法对数组进行过滤,筛选出偶数
let even_numbers: Veci32> = numbers.iter().filter(|&x| x % 2 == 0).cloned().collect();
// 输出筛选后的结果
println!(“Even numbers: {:?}”, even_numbers);
}
以上代码中,我们首先定义了一个包含整数的数组 numbers
,然后使用迭代器的 filter()
方法对数组进行过滤,筛选出其中的偶数。在 filter()
方法的闭包中,我们使用模运算来判断元素是否为偶数。最后使用 cloned()
方法来克隆每个偶数的值,并使用 collect()
方法将结果收集到一个新的数组 even_numbers
中。最终输出了筛选后的结果。
运行该程序,可以看到输出了数组中的所有偶数:
Even numbers: [2, 4, 6, 8, 10]
这个例子演示了 Rust 中迭代器的 filter()
方法的使用,以及如何结合其他方法来实现对数组的筛选操作。
Rust 迭代器方法
以下是一些 Rust 中常用的迭代器方法,以及它们的简要说明和示例:
方法名 | 描述 | 示例 |
---|---|---|
next() |
返回迭代器中的下一个元素。 | let mut iter = (1..5).into_iter(); while let Some(val) = iter.next() { println!("{}", val); } |
size_hint() |
返回迭代器中剩余元素数量的下界和上界。 | let iter = (1..10).into_iter(); println!("{:?}", iter.size_hint()); |
count() |
计算迭代器中的元素数量。 | let count = (1..10).into_iter().count(); |
nth() |
返回迭代器中第 n 个元素。 | let third = (0..10).into_iter().nth(2); |
last() |
返回迭代器中的最后一个元素。 | let last = (1..5).into_iter().last(); |
all() |
如果迭代器中的所有元素都满足某个条件,返回 true 。 |
let all_positive = (1..=5).into_iter().all(|x| x > 0); |
any() |
如果迭代器中的至少一个元素满足某个条件,返回 true 。 |
let any_negative = (1..5).into_iter().any(|x| x |
find() |
返回迭代器中第一个满足某个条件的元素。 | let first_even = (1..10).into_iter().find(|x| x % 2 == 0); |
find_map() |
对迭代器中的元素应用一个函数,返回第一个返回 Some 的结果。 |
let first_letter = "hello".chars().find_map(|c| if c.is_alphabetic() { Some(c) } else { None }); |
map() |
对迭代器中的每个元素应用一个函数。 |
let squares: Vec = (1..5).into_iter().map(|x| x * x).collect();
|
filter() |
保留迭代器中满足某个条件的元素。 | let evens: Vec = (1..10).into_iter().filter(|x| x % 2 == 0).collect(); |
filter_map() |
对迭代器中的元素应用一个函数,如果函数返回 Some ,则保留结果。 |
let chars: Vec = "hello".chars().filter_map(|c| if c.is_alphabetic() { Some(c.to_ascii_uppercase()) } else { None }).collect(); |
map_while() |
对迭代器中的元素应用一个函数,直到函数返回 None 。 |
let first_three = (1..).into_iter().map_while(|x| if x |
take_while() |
从迭代器中取出满足某个条件的元素,直到不满足为止。 | let first_five = (1..10).into_iter().take_while(|x| x >() |
skip_while() |
跳过迭代器中满足某个条件的元素,直到不满足为止。 | let odds: Vec = (1..10).into_iter().skip_while(|x| x % 2 == 0).collect(); |
for_each() |
对迭代器中的每个元素执行某种操作。 | let mut counter = 0; (1..5).into_iter().for_each(|x| counter += x); |
fold() |
对迭代器中的元素进行折叠,使用一个累加器。 | let sum: i32 = (1..5).into_iter().fold(0, |acc, x| acc + x); |
try_fold() |
对迭代器中的元素进行折叠,可能在遇到错误时提前返回。 | let result: Result = (1..5).into_iter().try_fold(0, |acc, x| if x == 3 { Err("Found the number 3") } else { Ok(acc + x) }); |
scan() |
对迭代器中的元素进行状态化的折叠。 | let sum: Vec = (1..5).into_iter().scan(0, |acc, x| { *acc += x; Some(*acc) }).collect(); |
take() |
从迭代器中取出最多 n 个元素。 | let first_five = (1..10).into_iter().take(5).collect::>() |
skip() |
跳过迭代器中的前 n 个元素。 | let after_five = (1..10).into_iter().skip(5).collect::>() |
zip() |
将两个迭代器中的元素打包成元组。 | let zipped = (1..3).zip(&['a', 'b', 'c']).collect::>() |
cycle() |
重复迭代器中的元素,直到无穷。 | let repeated = (1..3).into_iter().cycle().take(7).collect::>() |
chain() |
连接多个迭代器。 | let combined = (1..3).chain(4..6).collect::>() |
rev() |
反转迭代器中的元素顺序。 | let reversed = (1..4).into_iter().rev().collect::>() |
enumerate() |
为迭代器中的每个元素添加索引。 | let enumerated = (1..4).into_iter().enumerate().collect::>() |
peeking_take_while() |
取出满足条件的元素,同时保留迭代器的状态,可以继续取出后续元素。 | let (first, rest) = (1..10).into_iter().peeking_take_while(|&x| x |
step_by() |
按照指定的步长返回迭代器中的元素。 | let even_numbers = (0..10).into_iter().step_by(2).collect::>() |
fuse() |
创建一个额外的迭代器,它在迭代器耗尽后仍然可以调用 next() 方法。 |
let mut iter = (1..5).into_iter().fuse(); while iter.next().is_some() {} |
inspect() |
在取出每个元素时执行一个闭包,但不改变元素。 |
let mut counter = 0; (1..5).into_iter().inspect(|x| println!("Inspecting: {}", x)).for_each(|x| println!("Processing: {}", x));
|
same_items() |
比较两个迭代器是否产生相同的元素序列。 | let equal = (1..5).into_iter().same_items((1..5).into_iter()); |
总结
Rust 的迭代器是一个功能强大且灵活的工具,它允许以声明式的方式处理序列。迭代器的设计考虑了安全性、性能和表达力,是 Rust 语言的核心特性之一。通过迭代器,Rust 程序员可以写出既安全又高效的代码。
文章来源于互联网:Rust 迭代器
Bootstrap5 教程 Bootstrap 是全球最受欢迎的前端组件库,用于开发响应式布局、移动设备优先的 WEB 项目。 Bootstrap5 目前是 Bootstrap 的最新版本,是一套用于 HTML、CSS 和 JS 开发的开源工具集。它支持 Sa…