Rust中Chars迭代器调用next()为何会移除已遍历元素?
核心结论
你看到的行为差异本质是对比时观察的对象不匹配,和迭代器是否修改原始数据无关,Rust所有迭代器的next()行为逻辑是完全统一的。
先把两个例子的对比基准对齐
你在两个测试里打印的根本不是一类东西:
- 测试
Chars时,next()调用后你打印的是迭代器实例c本身 - 测试Vec迭代器时,
next()调用后你打印的是原始集合v1,不是迭代器v1_iter
只要把观察对象拉齐,你会发现二者表现没有任何区别:
// Vec迭代器打印迭代器自身的效果 let v1 = vec![1, 2, 3]; let mut v1_iter = v1.iter(); dbg!(v1_iter.next()); // 输出 Some(1) dbg!(v1_iter); // 输出 Iter([2, 3]),和Chars一样只显示剩余可遍历元素 dbg!(v1); // 输出 [1,2,3],原始集合从头到尾没被改动
// Chars打印原始字符串的效果 let origin_str = "hello"; let mut c = origin_str.chars(); dbg!(c.next()); // 输出 Some('h') dbg!(c); // 输出 Chars(['e','l','l','o']),仅展示迭代器剩余可遍历内容 dbg!(origin_str); // 输出 "hello",原始字符串完整保留,没有任何修改
迭代器的通用行为规则
所有实现了Iterator trait的类型,调用next()时只会做两个操作:
- 返回当前遍历位置的元素
- 将自身维护的遍历指针向后移动一个元素位
迭代器从来不会“修改原始值、删掉已经遍历过的元素”:
- 类似
chars()、vec.iter()这种基于不可变引用创建的迭代器,从根本上就没有修改原始数据的权限。Chars内部本质就是存了一个指向未遍历部分的字符串切片,调用next()时只是把内部切片的起始地址向后偏移当前字符对应的字节长度,原始字符串始终完整存放在内存里。它的Debug实现只是把内部持有的、还没遍历到的切片转成字符列表展示,才会让你产生“元素被删了”的错觉。 - 哪怕是
vec.into_iter()这种拿走集合所有权的迭代器,也不是遍历的时候逐个删除原集合的元素,只是迭代器持有了整个集合的所有权,按顺序把元素移出来而已。
不存在所谓“某类迭代器会消耗自身、移除已遍历元素”的特殊设计。任何迭代器打印实例本身时,展示的都是当前遍历指针之后剩余的可遍历内容,这只是迭代器内部遍历状态的直观体现,和原始数据是否被修改没有关联。
内容的提问来源于stack exchange,提问作者Finlay Weber
相关产品推荐
相关产品推荐

