当前位置: 首页 > news >正文

Rust中的for循环与迭代器

for 循环是迭代器的语法糖,而迭代器是 Rust 处理集合(如 VecHashMap)的核心抽象。

for循环

for 循环本质是自动遍历一个“可迭代对象”(实现 IntoIterator trait 的类型),底层逻辑如下:

  1. 对目标对象调用 into_iter() 方法,将其转换为迭代器(Iterator);
  2. 循环调用迭代器的 next() 方法,每次获取一个元素(Some(T));
  3. next() 返回 None 时,循环终止;
for item in collection {// ...
}// 会转换为以下近似代码
{let mut iter = IntoIterator::into_iter(collection);while let Some(item) = iter.next() {// ...}
}

用法

任何实现 IntoIterator 的类型,都能直接用 for 循环遍历。常有以下使用场景:

  • 遍历集合:处理 Vec、数组([T; N])、切片(&[T])等连续存储的集合;需注意所有权与借用模式,三种核心模式;
    • 所有权转移遍历:into_iter();转移所有权,T类型;
    • 不可变借用遍历:iter();不可变引用&T,需通过解引用(*)访问元素值。
    • 可变借用遍历:iter_mut();可变引用&mut T,需通过解引用(*)修改元素。
  • 计数循环:Range区间遍历
    • 左闭右开区间(a..b)
    • 左闭右闭区间(a..=b)
    • 反向计数(rev() 反向迭代):for i in (1..=5).rev()
  • 键值对遍历(HashMap/BTreeMap):返回key与value的引用;for (key, value) in &map
  • 遍历索引与值:enumerate() 适配器(返回 (index, value) 元组);for (idx, fruit) in fruits.iter().enumerate()
写法底层机制说明
for x in vv.into_iter()T(原值);所有权转移(消耗集合)
for x in &vv.iter()&T(不可变引用);不可变借用(只读集合)
for x in &mut vv.iter_mut()&mut T(可变引用);可变借用(修改集合)
for i in 0..nRange迭代器值拷贝
使用 'label
+ break 'label
控制流嵌套退出

绑定解构

迭代器遍历与后续适配器中元素的类型,是由trait中的Item确定的;对于引用类型,可通过&(不是取地址)进行解构。以iter()Item&T)遍历为例:

  • x:绑定 &T(保留引用),需通过 *x 解引用操作值;
  • &x:解构一层引用,直接绑定 T(原值),无需解引用。
fn type_of<T>(_: &T) -> &'static str {type_name::<T>()
}pub fn for_test() {let mut map = HashMap::new();map.insert("english", 80);map.insert("math", 90);// 用&解构过一次,输出:&str: i32for (&key, &value) in &map {println!("{}: {}", type_of(&key), type_of(&value));break;}// 输出:&&str: &i32for (key, value) in &map {println!("{}: {}", type_of(&key), type_of(&value));break;}
}

迭代器

Rust 的迭代器是实现了 Iterator trait 的对象;其不仅仅是一个“遍历工具”,还能惰性处理数据流,即惰性求值(lazy evaluation);多数方法不会立即执行,只是返回一个新的迭代器(直到 .collect().for_each() 等最终消费执行时,才计算)。

pub fn it_test() {// 1. 拆分单词为字符 → 2. 筛选小写字母 → 3. 转换为大写 → 4. 收集为 Vec<char>let words = vec!["Hello", "World", "Rust"];let uppercase_chars: Vec<char> = words.iter().flat_map(|s| s.chars()) // 扁平化:["H","e","l","l","o", ...].filter(|&c| c.is_ascii_lowercase()) // 筛选小写字母.map(|c| c.to_ascii_uppercase()) // 转换为大写.collect(); // 消耗迭代器,收集结果println!("{:?}", uppercase_chars); // 输出 ['E', 'L', 'L', 'O', 'O', 'R', 'L', 'D', 'U', 'S', 'T']let nums = vec![1, 2, 3, 4, 5];// 1. 求和(fold 折叠)let total = nums.iter().fold(1, |init, &x| init * x);println!("阶乘:{}", total); // 输出 120// 2. 查找第一个偶数let first_even = nums.iter().find(|&&x| x % 2 == 0);println!("第一个偶数:{:?}", first_even); // 输出 Some(2)// 3. 判断是否存在大于 5 的元素let has_gt5 = nums.iter().any(|&x| x > 5);println!("存在大于 5 的元素?{}", has_gt5); // 输出 false
}

适配器(Adapter)

适配器是返回新迭代器的方法,用于转换、筛选、组合原迭代器;多个适配器可组成“链式”,即通过把多个迭代器适配器组合在一起形成流水线式的数据处理流程。常见适配器:

适配器功能
map(f)对元素应用 f,转换元素类型
filter(f)保留满足条件 f的元素,返回 bool
flat_map(f)对元素应用 f,扁平化结果
rev()反向遍历(需迭代器实现 DoubleEndedIterator
skip(n)跳过前 n 个元素
take(n)取前 n 个元素,之后终止迭代
chain(iter2)拼接两个迭代器
enumerate()同时获取元素的索引和值,返回一个元组 (usize, T)

消耗性方法(Consuming Adapter)

消耗型方法会遍历迭代器、消耗元素,并返回最终结果(触发惰性求值),常见方法:

方法功能
collect<T>()收集元素为集合 T
count()返回元素个数
fold(init, f)折叠元素(聚合计算),init 为初始值
any(f)存在元素满足 f, 则返回 true
all(f)所有元素满足 f, 则返回 true
find(f)查找第一个满足 f 的元素,返回 Option<Item>
for_each(f)对每个元素执行 f,等价于 for
循环

无限迭代器

无限迭代器(如 iter::repeatRange::repeat),需通过 take(n) 等方法限制迭代次数,否则会陷入死循环。

常见无限迭代器:

  • iter::repeat(val):无限重复 val
  • iter::cycle():循环迭代原迭代器(原迭代器需是 Clone);
  • (0..).step_by(n):无限递增序列(步长 n)。

自定义迭代器

要创建自定义迭代器,只需实现 Iterator trait 的 next() 方法(其他方法为默认实现)。

Iterator trait 继承了 IntoIterator trait 的默认实现(IntoIterator::into_iter() 会直接返回迭代器本身(Self))。因此,只要一个类型实现了 Iterator::next(),就自动支持 for 循环遍历(本质是遍历迭代器自己)。

// pub trait Iterator {
//     type Item;
//
//     fn next(&mut self) -> Option<Self::Item>;
//
//     // 其他很多默认实现的方法(map, filter, fold等)
// }struct Counter {count: u32,upper: u32,
}impl Counter {fn new(upper: u32) -> Counter {Counter { count: 0, upper }}
}impl Iterator for Counter {type Item = u32;fn next(&mut self) -> Option<Self::Item> {self.count += 1;if self.count <= self.upper {Some(self.count)} else {None}}
}pub fn it_test() {for n in Counter::new(5) {println!("{}", n); // 输出:1~5}
}

自定义容器

容器要被 for 循环遍历,需让容器(或其引用)实现 IntoIterator trait:

  • iter() -> 返回不可变引用的迭代器
  • iter_mut() -> 返回可变引用的迭代器
  • into_iter() -> 转移所有权迭代器
// for x in my_container(消耗所有权)
impl<T> IntoIterator for MyContainer<T> {type Item = T;type IntoIter = MyIntoIter<T>;fn into_iter(self) -> Self::IntoIter {...}
}// for x in &my_container(不可变引用)
impl<'a, T> IntoIterator for &'a MyContainer<T> {type Item = &'a T;type IntoIter = MyIter<'a, T>;fn into_iter(self) -> Self::IntoIter {...}
}// for x in &mut my_container(可变引用)
impl<'a, T> IntoIterator for &'a mut MyContainer<T> {type Item = &'a mut T;type IntoIter = MyIterMut<'a, T>;fn into_iter(self) -> Self::IntoIter {...}
}

以一个环形缓冲区为例,实现三种for操作:

use core::slice;
use std::mem::MaybeUninit;pub struct RingBuffer<T, const N: usize> {data: [MaybeUninit<T>; N],head: usize,len: usize,
}impl<T, const N: usize> RingBuffer<T, N> {pub fn new() -> Self {Self {data: unsafe { MaybeUninit::uninit().assume_init() },head: 0,len: 0,}}pub fn len(&self) -> usize {self.len}pub fn push(&mut self, value: T) -> Result<(), &str> {if self.len == N {return Err("buffer full");}let tail = (self.head + self.len) % N;self.data[tail] = MaybeUninit::new(value);self.len += 1;Ok(())}pub fn pop(&mut self) -> Option<T> {if self.len == 0 {return None;}let val = std::mem::replace(&mut self.data[self.head], MaybeUninit::uninit());self.head = (self.head + 1) % N;self.len -= 1;Some(unsafe { val.assume_init() })}/// 获取不可变切片视图(连续或分段)fn as_slices(&self) -> (&[T], &[T]) {unsafe {let head_ptr = self.data.as_ptr().add(self.head) as *const T;if self.head + self.len <= N {(slice::from_raw_parts(head_ptr, self.len), &[])} else {let first_len = N - self.head;let rest = (self.head + self.len) % N;(slice::from_raw_parts(head_ptr, first_len),slice::from_raw_parts(self.data.as_ptr() as *const T, rest),)}}}fn as_mut_slice(&mut self) -> (&mut [T], &mut [T]) {unsafe {let head_ptr = self.data.as_mut_ptr().add(self.head) as *mut T;if self.head + self.len <= N {(slice::from_raw_parts_mut(head_ptr, self.len), &mut [])} else {let first_len = N - self.head;let rest = (self.head + self.len) % N;(slice::from_raw_parts_mut(head_ptr, first_len),slice::from_raw_parts_mut(self.data.as_ptr() as *mut T, rest),)}}}
}impl<T, const N: usize> Drop for RingBuffer<T, N> {fn drop(&mut self) {for i in 0..self.len {let idx = (self.head + i) % N;unsafe {self.data[idx].assume_init_drop();}}}
}pub struct Iter<'a, T> {first: slice::Iter<'a, T>,second: slice::Iter<'a, T>,
}
impl<T, const N: usize> RingBuffer<T, N> {pub fn iter(&self) -> Iter<'_, T> {let (first, second) = self.as_slices();Iter {first: first.iter(),second: second.iter(),}}
}
impl<'a, T> Iterator for Iter<'a, T> {type Item = &'a T;fn next(&mut self) -> Option<Self::Item> {self.first.next().or_else(|| self.second.next())}
}pub struct IterMut<'a, T> {first: slice::IterMut<'a, T>,second: slice::IterMut<'a, T>,
}
impl<T, const N: usize> RingBuffer<T, N> {pub fn iter_mut(&mut self) -> IterMut<'_, T> {let (first, second) = self.as_mut_slice();IterMut {first: first.iter_mut(),second: second.iter_mut(),}}
}
impl<'a, T> Iterator for IterMut<'a, T> {type Item = &'a mut T;fn next(&mut self) -> Option<Self::Item> {self.first.next().or_else(|| self.second.next())}
}pub struct IntoIter<T, const N: usize> {buff: RingBuffer<T, N>,
}
impl<T, const N: usize> Iterator for IntoIter<T, N> {type Item = T;fn next(&mut self) -> Option<Self::Item> {self.buff.pop()}
}// IntoIterator Trait
impl<T, const N: usize> IntoIterator for RingBuffer<T, N> {type Item = T;type IntoIter = IntoIter<T, N>;fn into_iter(self) -> Self::IntoIter {IntoIter { buff: self }}
}
impl<'a, T, const N: usize> IntoIterator for &'a RingBuffer<T, N> {type Item = &'a T;type IntoIter = Iter<'a, T>;fn into_iter(self) -> Self::IntoIter {self.iter()}
}
impl<'a, T, const N: usize> IntoIterator for &'a mut RingBuffer<T, N> {type Item = &'a mut T;type IntoIter = IterMut<'a, T>;fn into_iter(self) -> Self::IntoIter {self.iter_mut()}
}pub fn ringbuff_test() {let mut buf: RingBuffer<i32, 4> = RingBuffer::new();buf.push(10).unwrap();buf.push(20).unwrap();buf.push(30).unwrap();println!("Iterate immutably:");for v in &buf {println!("  value = {v}");}println!("Iterate mutably:");for v in &mut buf {*v += 1;}println!("Iterate by value:");for v in buf {println!("  moved = {v}");}
}
http://www.dtcms.com/a/615175.html

相关文章:

  • 食品网站建设方案wordpress 源码出售
  • 深度学习:深入理解 Softmax 激活函数
  • 【持续更新】2025华为OD机试2025双机位A卷机考真题库清单含考点说明(Java/Python/JS/C++/Go)
  • 珠海做网站设计WordPress完全删除
  • 手表网站登录页背景图建设网站推广广告图
  • 小区百货店网怎么做网站开封公司网站如何制作
  • 保研贴 | 2025年(22级)四非计算机大类专业保研历程记录
  • java基础-14 : stream流
  • 巨鹿网站建设公司怎样做网络推广挣钱
  • 网站开发管理方案合肥网站建设合肥做网站
  • Linux宝塔面板安装脚本(正式版:11.2.0)
  • 设计师网站推荐免费的自助建站
  • C Primer Plus 13.10 复习题
  • 营销网站建设网站设计sem竞价
  • 58同城网站官网网站首页设置伪静态
  • 基于springboot框架的网上商城系统的设计与实现
  • 免费做网站方法北京木马工业设计
  • 前端JS深拷贝实现,解决对象引用问题
  • C语言程序编译软件 | 帮助你快速编写和调试C语言程序的工具
  • 搜索网站开发背景做百度移动网站点
  • 网站的关键词怎么设置电子商务市场营销
  • C++进阶:coroutine 协程
  • 网站开发学什么数据库上海seo课程
  • 网站销售的优势crm客户关系管理系统源码
  • Blender:法线图黑白图
  • 做网站要不要钱济南网站优化公司哪家好
  • 编译动态库时只需要知道函数的声明,与可执行文件不同
  • 【OpenGL】CMake报错解决:Error in configuration process,project files may be invalid.
  • AI有利也有坏
  • 网站 备案规定付费推广