本节学习Rust中的控制流语句,也就是循环/条件/模式匹配。
Rust中没有js或java中的for循环,没有三目表达式,也没有switch-case,try-catch语句,这一点可能是刚写Rust最不习惯的地方。
if
基本用法
和js或java类似,但是条件判断不用加括号------在Rust中括号是单元类型,用在特殊地方,因此很多js中需要加括号的地方,Rust中都不用。
rust
let number = 7;
if number < 0 {
println!("负数");
} else if number == 0 {
println!("零");
} else if number < 10 {
println!("一位正数");
} else {
println!("两位数或更大");
}
let if
在Rust中,语句(Statement)是执行一些操作但不返回值的指令,而表达式(Expression)计算并返回一个值。Rust中大部分控制流结构都是表达式,可以返回值。 这使得代码更简洁,表达能力更强。同时,Rust的模式匹配非常强大,可以处理各种复杂的数据结构。
这里可使用let直接获取if表达式的返回结果
rust
// 可以使用块表达式
let description = if score >= 60 {
let message = format!("及格,分数是 {}", score);
message // 返回字符串
} else {
"不及格".to_string()
};
println!("{}", description);
循环
Rust中的循环语句有三种:loop,while和for
loop-无限循环
loop是无限循环,用break跳出。
基本用法
rust
let mut count = 0;
// 无限循环
loop {
count += 1;
println!("循环次数: {}", count);
// 跳过某些迭代
if count % 2 == 0 {
continue; // 跳过偶数
}
if count >= 5 {
break; // 退出循环
}
}
let loop
rust
let result = loop {
count += 1;
if count == 10 {
break count * 2; // 循环可以返回值
}
};
println!("结果是: {}", result); // 20
嵌套循环和标签
rust
// 嵌套循环和标签
'outer: loop {
println!("进入外层循环");
let mut inner_count = 0;
loop {
println!("内层循环: {}", inner_count);
inner_count += 1;
if inner_count >= 3 {
break; // 只退出内层循环
}
if inner_count == 2 {
break 'outer; // 退出带标签的外层循环
}
}
println!("这行不会执行");
}
while-条件循环
while类似js中的while-do语句,不过更简单。
rust
let mut number = 3;
// 基本 while 循环
while number != 0 {
println!("倒计时: {}", number);
number -= 1;
}
println!("发射!");
for循环
Rust中没有类似i++的语法,无法使用C风格的三表达式for循环 。Rust中的for循环类似js中的for in
1. 遍历Range
rust
// 1. 遍历范围 (Range)
println!("范围 0..5:");
for i in 0..5 { // 不包含5: 0,1,2,3,4
print!("{} ", i);
}
println!();
println!("范围 0..=5:");
for i in 0..=5 { // 包含5: 0,1,2,3,4,5
print!("{} ", i);
}
println!();
2. 遍历数组
rust
// 2. 遍历数组
let numbers = [1, 2, 3, 4, 5];
println!("\n遍历数组:");
for number in numbers {
print!("{} ", number);
}
println!();
// 遍历数组带索引
println!("\n遍历数组带索引:");
for (index, &value) in numbers.iter().enumerate() {
println!("numbers[{}] = {}", index, value);
}
3. 遍历向量
rust
// 3. 遍历向量 (Vec)
let vec = vec!["苹果", "香蕉", "橙子"];
println!("\n遍历向量:");
for fruit in &vec {
print!("{} ", fruit);
}
println!();
4. 遍历字符串
rust
// 4. 遍历字符串字符
let text = "Rust";
println!("\n遍历字符串字符:");
for ch in text.chars() {
print!("{} ", ch);
}
println!();
// 遍历字符串字节
println!("\n遍历字符串字节:");
for byte in text.bytes() {
print!("{} ", byte);
}
println!();
5. 反向遍历
rust
// 7. 反向遍历
println!("\n反向遍历:");
for i in (0..5).rev() {
print!("{} ", i); // 4, 3, 2, 1, 0
}
println!();
6. 带步长遍历
rust
// 6. 带步长的遍历
println!("\n带步长的遍历:");
for i in (0..=10).step_by(2) {
print!("{} ", i); // 0, 2, 4, 6, 8, 10
}
println!();
模式匹配(match)
match相当于switch-case
基本用法
rust
let number = 42;
// 基本 match,类似 switch
match number {
1 => println!("一"),
2 | 3 | 5 | 7 | 11 => println!("小于12的质数"),
13..=19 => println!("十几岁"),
20..=39 => println!("二十多到三十多"),
40..=49 => println!("四十多岁"),
_ => println!("其他数字"), // 默认情况
}
// match 是表达式,可以返回值
let description = match number {
0 => "零",
1 => "一",
2 => "二",
_ => "其他",
};
println!("描述: {}", description);
// 匹配布尔值
let flag = true;
let status = match flag {
true => "开启",
false => "关闭",
};
println!("状态: {}", status);
复杂模式匹配
match可以匹配元组,枚举,Option,Result和结构体
rust
// 1. 匹配元组
let point = (2, 3);
match point {
(0, 0) => println!("原点"),
(0, y) => println!("在Y轴上,y = {}", y),
(x, 0) => println!("在X轴上,x = {}", x),
(x, y) => println!("点 ({}, {})", x, y),
}
// 2. 匹配枚举
enum Direction {
Up,
Down,
Left,
Right,
}
let dir = Direction::Right;
match dir {
Direction::Up => println!("向上"),
Direction::Down => println!("向下"),
Direction::Left => println!("向左"),
Direction::Right => println!("向右"),
}
// 3. 带数据的枚举
enum Shape {
Circle(f64), // 半径
Rectangle(f64, f64), // 宽, 高
Square(f64), // 边长
}
let shape = Shape::Rectangle(3.0, 4.0);
match shape {
Shape::Circle(radius) => {
println!("圆形,半径: {:.2}", radius);
}
Shape::Rectangle(width, height) => {
println!("矩形,宽: {:.2}, 高: {:.2}", width, height);
}
Shape::Square(side) => {
println!("正方形,边长: {:.2}", side);
}
}
// 4. 匹配 Option
let maybe_value: Option<i32> = Some(42);
match maybe_value {
Some(x) => println!("有值: {}", x),
None => println!("没有值"),
}
// 5. 匹配 Result
let result: Result<i32, &str> = Ok(42);
match result {
Ok(value) => println!("成功: {}", value),
Err(error) => println!("错误: {}", error),
}
// 5. 匹配结构体
struct Point {
x: i32,
y: i32,
}
let point = Point { x: 0, y: 7 };
match point {
Point { x: 0, y: 0 } => println!("原点"),
Point { x, y: 0 } => println!("在X轴上,x = {}", x),
Point { x: 0, y } => println!("在Y轴上,y = {}", y),
Point { x, y } => println!("点({}, {})", x, y),
}
@绑定
Rust中的@绑定(也称为绑定模式)允许在模式匹配的同时,将匹配的值绑定到一个变量上。这在需要对匹配的值进行进一步操作时非常有用,尤其是在嵌套模式中。
rust
// @ 绑定
enum Message {
Hello { id: i32 },
}
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello { id: id_variable @ 3..=7 } => {
println!("找到范围内的id: {}", id_variable);
}
Message::Hello { id: 10..=12 } => {
println!("找到另一个范围内的id");
}
Message::Hello { id } => {
println!("找到其他id: {}", id);
}
}
引申:Option和Result
Option<T> 和 Result<T, E>是 Rust 中用于处理可能缺失的值和可能失败的操作的核心类型。它们是 Rust 安全编程哲学的基石,强制在编译时处理所有可能的错误情况。
Rust中没有undefined类型,也没有try-catch语句,而用Option和Result处理这两者。
Option的基本用法
rust
// 在Rust中,使用Option<T>来表示一个值可能存在或可能缺失
let some_value: Option<i32> = Some(5);
let no_value: Option<i32> = None;
// 函数可能返回None
fn find_item(id: u32) -> Option<String> {
if id == 1 {
Some("Item found".to_string())
} else {
None // 相当于JavaScript中的undefined
}
}
Result的基本用法
rust
// 函数返回Result表示可能失败
fn open_file(path: &str) -> Result<File, std::io::Error> {
match File::open(path) {
Ok(file) => Ok(file),
Err(e) => Err(e), // 返回错误而不是抛出异常
}
}
// 使用match处理Result
match open_file("test.txt") {
Ok(file) => println!("文件打开成功"),
Err(e) => println!("打开文件失败: {}", e),
}
Rust中的?操作符
?操作符在Rust中用于错误传播,它简化了Result和Option类型的处理,使代码更简洁。其基本作用是对Result或Option值进行判断:如果是Ok/Some,就解包取出内部值继续执行;如果是Err/None,则提前返回该错误或None。
rust
fn example() -> Result<i32, String> {
let x: Result<i32, String> = Ok(5);
let y = x?; // 如果 x 是 Ok(5),则 y = 5
// 如果 x 是 Err(e),则立即返回 Err(e)
Ok(y * 2)
}
if let和while let
if let 是一种更简洁的方式,用于处理只匹配一个模式的值而忽略其他模式的情况。while let 允许只要模式匹配就一直进行循环。
scss
// 使用 if let
let some_value = Some(42);
if let Some(x) = some_value {
println!("值是: {}", x);
}
// 条件循环匹配
while let Some(item) = iter.next() {
// ...
}