前端都能看懂的Rust入门教程(三)——控制流语句

本节学习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() {
    // ...
}
相关推荐
Mr Xu_4 小时前
Vue 3 中计算属性的最佳实践:提升可读性、可维护性与性能
前端·javascript
汤姆yu4 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶4 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
野犬寒鸦4 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
jerrywus4 小时前
我写了个 Claude Code Skill,再也不用手动切图传 COS 了
前端·agent·claude
玖月晴空5 小时前
探索关于Spec 和Skills 的一些实战运用-Kiro篇
前端·aigc·代码规范
子兮曰5 小时前
深入理解滑块验证码:那些你不知道的防破解机制
前端·javascript·canvas
Java编程爱好者5 小时前
Seata实现分布式事务:大白话全剖析(核心讲透AT模式)
后端
神奇小汤圆5 小时前
比MySQL快800倍的数据库:ClickHouse的性能秘密
后端