Rust 没有传统的 for(;;),for 只是语法糖。这篇用编译器的 HIR 输出直接看它被展开成什么,再手写同样的 match + loop 验证行为一致,用带打印的自定义迭代器数调用次数。
源码:
pub fn total(v: &[i32]) -> i32 {
let mut s = 0;
for x in v { s += x; }
s
}
-Z unpretty=hir 输出(去掉前面的 prelude 行):
#[attr = PreludeImport]
use std::prelude::rust_2024::*;
fn total(v: &'_ [i32])
->
i32 {
let mut s = 0;
{
let _t =
match into_iter(v) {
mut iter =>
loop {
match next(&mut iter) {
None {} => break,
Some { 0: x } => { s += x; }
}
},
};
_t
};
s
}HIR 展开使用了 RUSTC_BOOTSTRAP=1 与 -Z unpretty=hir(稳定版编译器上打开 nightly 选项),输出格式随编译器版本变化。三种遍历写法见IntoIterator 的三种遍历方式。
源码:
1 | fn main() {
2 | let v = vec![1, 2, 3, 4, 5, 6];
3 | let mut a = Vec::new();
4 | for x in &v { if x % 2 == 0 { continue; } if *x > 4 { break; } a.push(*x); }
5 | let mut b = Vec::new();
6 | match IntoIterator::into_iter(&v) {
7 | mut iter => loop {
8 | match Iterator::next(&mut iter) {
9 | None => break,
10 | Some(x) => { if x % 2 == 0 { continue; } if *x > 4 { break; } b.push(*x); }
11 | }
12 | }
13 | }
14 | println!("for: {:?} 手写展开: {:?} 相同: {}", a, b, a == b);
15 | }
编译:成功
运行(退出码 0):
for: [1, 3] 手写展开: [1, 3] 相同: true 编译:成功
运行(退出码 0):
into_iter() 被调用
next() 被调用,n = 0
循环体 x = 1
next() 被调用,n = 1
循环体 x = 2
next() 被调用,n = 2
循环体 x = 3
next() 被调用,n = 3
循环结束自定义迭代器见自定义 Iterator。
源码:
1 | fn main() {
2 | let mut v = vec![1, 2, 3];
3 | for x in &v { if *x == 2 { v.push(4); } }
4 | }
编译:失败
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> <实验目录>/src/u68d.rs:3:32
|
3 | for x in &v { if *x == 2 { v.push(4); } }
| -- ^^^^^^^^^ mutable borrow occurs here
| |
| immutable borrow occurs here
| immutable borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0502`.
编译:成功
运行(退出码 0):
下标写法可以改: [1, 20, 3, 40]
iter_mut 写法: [2, 21, 4, 41]
0..n 循环 3 次
循环体里把 m 改成 100 之后,仍然只循环 3 次