Skip to content

控制流

rust中有if和match两种控制流

1.条件表达式

1.1 if分支

if 是最基本的条件控制结构,用于根据条件执行不同的代码分支:

  • 若只有一个条件,使用if即可,判断条件写在if后面
  • 若有两个条件,可以使用else分支处理另一个条件
  • 若大于两个条件,可以在ifelse直接使用else if处理其他的条件,判断条件写在else if后面
rust
let number = 6;

if number > 5 {
    println!("数字大于5");
} else if number < 0 {
    println!("数字小于0");
} else {
    println!("数字在 0 ~ 5 之间");
}

这是最传统的 if 用法,根据条件执行相应的代码块。当条件为真时,执行 if 后的代码块;当条件为假且有 else 分支时,执行 else 后的代码块。

1.2 if表达式化

与其他语言不同,Rust 中的 if 不仅是语句,更是表达式,可以返回值:

rust
let number = 6;

let result = if number % 2 == 0 {
    "偶数"
} else {
    "奇数"
};

println!("数字 {} 是 {}", number, result);

这里的关键概念是:大括号 {} 的最后一个表达式就是该代码块的返回值。注意 "偶数""奇数" 后面都没有分号,这意味着它们是表达式而不是语句,会作为代码块的返回值。

因此在Rust中没有三元表达式?:,因为if本身作为表达式就可以完成对应的功能。

例如以上代码在C++中可以用?:完成:

cpp
String str = number % 2 == 0 ? "偶数" : "奇数";

1.3 if表达式的类型要求

由于 if 是表达式,编译器需要在编译时确定其返回的类型,因此所有分支必须返回相同类型

rust
let condition = true;

// 正确:所有分支返回相同类型
let number = if condition {
    5
} else {
    6
};

println!("number = {}", number);

// 错误示例(会编译失败):
let mixed = if condition {
    5        // 整数类型
} else {
    "six"    // 字符串类型
};

这个限制确保了类型安全,编译器可以在编译时就确定变量的类型,避免运行时的类型错误。

1.4 match分支匹配

matchRust 中更强大的分支控制结构,可以匹配多种模式:

rust
let number = 3;

match number {
    1 => println!("一"),
    2 => println!("二"),
    3 => println!("三"),
    _ => println!("其他"),
}

match 通过模式匹配来决定执行哪个分支。每个分支由模式和对应的代码组成,用 => 连接。_ 是通配符,匹配所有其他情况,通过将其放置于其他分支之后

它类似于其他语言的switch语句,但是功能性远比switch强大。

  • match 必须覆盖被匹配值的所有可能情况,这被称为"穷尽性"要求:
rust
enum Direction {
    North,
    South,
    East,
    West,
}

let dir = Direction::North;

match dir {
    Direction::North => "向北前进",
    Direction::South => "向南前进",
    Direction::East => "向东前进",
    Direction::West => "向西前进",
}

穷尽性检查是编译时进行的,确保你不会遗漏任何情况。这大大减少了运行时错误的可能性。

  • match 支持多种复杂的模式匹配:
rust
let number = 7;

match number {
    1 => println!("一"),
    2 | 3 => println!("二或三"),  // 多值匹配
    4..=6 => println!("四到六"),  // 范围匹配
    _ => println!("其他"),
}
  • 多值匹配:使用 | 可以匹配多个值
  • 范围匹配:使用 ..= 可以匹配一个范围内的值

模式匹配非常繁杂,功能非常强大,后续会开专门的章节讲解,本博客只是让大家了解存在这样一种分支处理的语法。

关于match,在后面枚举中还会继续介绍

2.循环控制

Rust提供了三种循环表达式,分别是whileloopfor in,用法和其他语言基本类似。

2.1 loop

loop 创建一个无限循环,是最基本的循环结构:

rust
let mut counter = 0;

loop {
    counter += 1;
    println!("计数: {}", counter);
}

loop 会无限执行,是最直接的循环控制方式。当其内部不含任何break,那么整个表达式返回!类型。

2.2 while

while 循环格式如下:

rust
while 条件 {
	// 循环体
}

在条件为真时持续执行循环体,否则就退出循环。

示例:

rust
let mut number = 5;

while number > 0 {
    println!("倒计时: {}", number);
    number -= 1;
}

println!("发射!");

while 在每次循环开始前检查条件,条件为假时退出循环。这比 loop + if + break 的组合更简洁。

while 循环中也可以使用 break 提前退出,但与 loop 不同的是,while 循环不允许 break 携带返回值:

rust
let mut count = 0;

while count < 10 {
    count += 1;
    
    if count == 5 {
        break;  // 可以 break,但不能 break 值
    }
    
    println!("计数: {}", count);
}

let result = while condition { break 42; };  // 错误!while 不能返回值

这是因为 while 循环的条件可能一开始就为假,那样循环体根本不会执行,无法确定返回值。

有人可能就有疑问:已经有while了,为什么还需要loop?因为while true 不就可以实现死循环吗?

Rust一切皆表达式,表达式=副作用+返回值,loopwhile true 的副作用类似,都是死循环,但是返回值有很大差别。不要用while true循环来代替loop实现死循环,本文后半部分讲到函数会给一个反例。

2.3 for...in...

for 循环用于遍历集合或迭代器,语法如下:

rust
for var in 迭代器 {
    
}
  • var为当前迭代对象
  • for循环的内容必须是可迭代迭代器,比如数组

示例:

rust
let numbers = [1, 2, 3, 4, 5];

for num in numbers {
    println!("数字: {}", num);
}

for 循环会自动遍历可迭代对象的每个元素。这是 Rust 中最常用的循环方式,既安全又高效。

in后可以放任何可遍历的迭代器,具体的深入原理会在后续的迭代器章节讲解。在这之前最常见的写法就是:

rust
for var in 数组名 {
}

能看懂即可,此处的var就是数组的每一个元素。

同样的,for in也是一个表达式,返回单元类型(),并且break不允许携带返回值==。

2.4 break 和 continue

在循环中,break 用于退出循环,continue 用于跳过本次迭代:

rust
let mut count = 0;

loop {
    count += 1;
    
    if count % 2 == 0 {
        continue;  // 跳过偶数
    }
    
    if count > 10 {
        break;     // 超过10就退出
    }
    
    println!("奇数: {}", count);
}

continue 会跳过当前循环的剩余代码,直接进入下一次循环。break 会立即退出整个循环。

对于loop来说,break是一种常见的终止循环手段。那么当loop不是死循环,返回的值就不是!了,具体返回的值是什么取决于break

2.5 break 返回值

loop循环也是表达式,可以通过 break 返回值,在break与分号;之间可以携带一个返回值。

rust
let mut num = 1;

let result = loop {
    if num % 2 == 0 {
        break num;  // 返回 num 的值
    }
    num += 1;
};

println!("第一个偶数: {}", result);

这里 break num 表示退出循环并返回 num 的值。整个 loop 表达式的值就是 break 后面的值。

break;的时候,也就是break不携带值,此时返回的是一个()单元类型。

只有loop循环可以用break返回值,其他两种循环不可以

2.6 标签跳转

当有嵌套循环时,可以使用标签来指定 breakcontinue 要影响哪个循环,语法如下:

rust
'标签A loop {

	'标签B while ... {
		if ... {
			break '标签A;
		} else {
			continue `标签A;
		}
	}
	
}

语法中,'标签A代表外层循环,'标签B代表内层循环,标签必须以单引号开头。在while 循环内部,可以通过break '标签Acontinue '标签A 直接控制外层循环。

示例:

rust
'outer: loop {
    println!("进入外层循环");
    
    'inner: loop {
        println!("进入内层循环");
        break 'outer;  // 跳出外层循环
    }
    
    println!("这行代码不会执行");
}

println!("退出所有循环");

这种标签这在复杂的嵌套循环中很有用,可以快速跳出多层循环。

当使用标签跳转时,break 也可以携带返回值,但只能在 loop 循环中使用:

rust
let result = 'outer: loop {
    let mut inner_count = 0;
    
    'inner: while inner_count < 5 {
        inner_count += 1;
        println!("内层计数: {}", inner_count);
        
        if inner_count == 3 {
            break 'outer inner_count;  // 跳出外层循环并返回值
        }
    }
    
    println!("这行代码不会执行");
};

println!("返回值: {}", result);  // 输出: 返回值: 3

此处在 break 'outer的同时,携带了一个返回值inner_count,因为'outer是外层的loop循环,所以允许返回。

标签跳转的返回值只能用于 loop 循环,whilefor 循环即使使用标签也不能返回值。

要求必须在编译期拿到结果,于是发生冲突就报错了。

MIT Licensed