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: i32
    for (&key, &value) in &map {
        println!("{}: {}", type_of(&key), type_of(&value));
        break;
    }

    // 输出:&&str: &i32
    for (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}");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值