🦀 第03课:控制流与函数

控制流和函数是任何编程语言的核心构造块。Rust在这方面有独特的设计——if是表达式、循环有丰富控制、函数支持多种参数模式。本课将深入这些特性。

入门基础 第3/25课

学习目标:掌握if表达式、各种循环、函数定义与参数、表达式与语句的区别

🔀 if表达式

Rust的if不同于大多数语言——它是表达式,有返回值!

基本if-else

fn main() {
    let number = 7;
    
    if number > 10 {
        println!("大于10");
    } else if number > 5 {
        println!("大于5但不大于10");
    } else {
        println!("5或更小");
    }
}
大于5但不大于10

if是表达式 —— 可以赋值!

fn main() {
    let condition = true;
    let number = if condition { 5 } else { 6 };
    println!("number = {}", number);
    
    // 实际应用:根据条件选择不同消息
    let score = 85;
    let grade = if score >= 90 {
        "A"
    } else if score >= 80 {
        "B"
    } else if score >= 70 {
        "C"
    } else if score >= 60 {
        "D"
    } else {
        "F"
    };
    println!("分数{} -> 等级{}", score, grade);
    
    // ⚠️ 两个分支的类型必须一致!
    // let x = if true { 5 } else { "six" };  // ❌ 类型不匹配
}
number = 5 分数85 -> 等级B

✅ 验证通过

💡 关键区别:Rust的if条件必须是bool类型,不会像C/JS那样自动转换。if 0 {}会编译错误。

🔁 循环

Rust有三种循环:loopwhilefor。它们都可以作为表达式使用。

loop —— 无限循环

fn main() {
    // 基本loop
    let mut counter = 0;
    let result = loop {
        counter += 1;
        if counter == 10 {
            break counter * 2;  // break可以带返回值!
        }
    };
    println!("result = {}", result);  // 20
    
    // 循环标签(嵌套循环时用)
    let mut count = 0;
    'outer: loop {
        println!("外层 count = {}", count);
        let mut remaining = 10;
        
        loop {
            println!("  内层 remaining = {}", remaining);
            if remaining == 9 {
                break;  // 只跳出内层
            }
            if count == 2 {
                break 'outer;  // 跳出外层!
            }
            remaining -= 1;
        }
        count += 1;
    }
    println!("循环结束");
}
result = 20 外层 count = 0 内层 remaining = 10 内层 remaining = 9 外层 count = 1 内层 remaining = 10 内层 remaining = 9 外层 count = 2 内层 remaining = 10 内层 remaining = 9 循环结束

✅ 验证通过

while —— 条件循环

fn main() {
    let mut number = 3;
    while number != 0 {
        println!("{}!", number);
        number -= 1;
    }
    println!("发射!🚀");
    
    // while遍历数组(不推荐,用for更好)
    let arr = [10, 20, 30, 40, 50];
    let mut index = 0;
    while index < arr.len() {
        println!("arr[{}] = {}", index, arr[index]);
        index += 1;
    }
}
3! 2! 1! 发射!🚀 arr[0] = 10 arr[1] = 20 arr[2] = 30 arr[3] = 40 arr[4] = 50

✅ 验证通过

for —— 遍历循环(最常用)

fn main() {
    // 遍历数组
    let arr = [10, 20, 30, 40, 50];
    for element in arr {
        println!("元素: {}", element);
    }
    
    // 带索引遍历
    for (i, &v) in arr.iter().enumerate() {
        println!("索引{}: 值{}", i, v);
    }
    
    // 范围
    for i in 0..5 {       // 0,1,2,3,4
        print!("{} ", i);
    }
    println!();
    
    for i in 1..=5 {      // 1,2,3,4,5
        print!("{} ", i);
    }
    println!();
    
    // 反向
    for i in (1..=5).rev() {
        print!("{} ", i);
    }
    println!();
    
    // 步进(通过迭代器方法)
    for i in (0..20).step_by(5) {
        print!("{} ", i);
    }
    println!();
    
    // continue和break
    for n in 1..=10 {
        if n % 2 == 0 {
            continue;  // 跳过偶数
        }
        if n > 7 {
            break;     // 大于7停止
        }
        print!("{} ", n);
    }
    println!();
}
元素: 10 元素: 20 元素: 30 元素: 40 元素: 50 索引0: 值10 索引1: 值20 索引2: 值30 索引3: 值40 索引4: 值50 0 1 2 3 4 1 2 3 4 5 5 4 3 2 1 0 5 10 15 1 3 5 7

✅ 验证通过

⚡ 函数

函数定义

// 无参数无返回值
fn say_hello() {
    println!("你好,Rust!");
}

// 有参数和返回值
fn add(a: i32, b: i32) -> i32 {
    a + b  // 注意:无分号!最后一个表达式就是返回值
}

// 多种返回方式
fn absolute(x: i32) -> i32 {
    if x >= 0 {
        x        // if表达式返回
    } else {
        -x
    }
}

// 提前返回用return
fn factorial(n: u64) -> u64 {
    if n <= 1 {
        return 1;  // 提前返回
    }
    n * factorial(n - 1)  // 递归
}

fn main() {
    say_hello();
    println!("3 + 5 = {}", add(3, 5));
    println!("|−7| = {}", absolute(-7));
    println!("5! = {}", factorial(5));
}
你好,Rust! 3 + 5 = 8 |−7| = 7 5! = 120

✅ 验证通过

⚠️ 表达式 vs 语句:
- a + b(无分号)→ 表达式,有返回值
- a + b;(有分号)→ 语句,返回()
- 函数最后一个表达式不加;就作为返回值,加了;则返回()

函数参数模式

// 可变参数
fn increment(mut x: i32) -> i32 {
    x += 1;
    x
}

// 引用参数(借用)
fn greet(name: &str) -> String {
    format!("你好,{}!", name)
}

// 可变引用
fn append_world(s: &mut String) {
    s.push_str(" World");
}

// 默认值?Rust没有默认参数,但可以用Option
fn greet_with_title(name: &str, title: Option<&str>) -> String {
    match title {
        Some(t) => format!("{}, {}", t, name),
        None => format!("{}", name),
    }
}

// 切片参数
fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    s
}

fn main() {
    println!("increment(5) = {}", increment(5));
    println!("{}", greet("Rust"));
    
    let mut msg = String::from("Hello");
    append_world(&mut msg);
    println!("拼接后: {}", msg);
    
    println!("{}", greet_with_title("Alice", Some("Dr.")));
    println!("{}", greet_with_title("Bob", None));
    
    let text = String::from("hello world");
    println!("第一个词: {}", first_word(&text));
}
increment(5) = 6 你好,Rust! 拼接后: Hello World Dr., Alice Bob 第一个词: hello

✅ 验证通过

函数作为值

fn add(a: i32, b: i32) -> i32 { a + b }
fn multiply(a: i32, b: i32) -> i32 { a * b }

fn apply(f: fn(i32, i32) -> i32, a: i32, b: i32) -> i32 {
    f(a, b)
}

fn main() {
    // 函数指针
    let op: fn(i32, i32) -> i32 = add;
    println!("5 + 3 = {}", op(5, 3));
    
    // 作为参数传递
    println!("apply(add, 5, 3) = {}", apply(add, 5, 3));
    println!("apply(multiply, 5, 3) = {}", apply(multiply, 5, 3));
    
    // 函数存储在集合中
    let operations: [fn(i32, i32) -> i32; 3] = [add, multiply, |a, b| a - b];
    for (i, op) in operations.iter().enumerate() {
        println!("操作{}: apply(10, 3) = {}", i, op(10, 3));
    }
}
5 + 3 = 8 apply(add, 5, 3) = 8 apply(multiply, 5, 3) = 15 操作0: apply(10, 3) = 13 操作1: apply(10, 3) = 30 操作2: apply(10, 3) = 7

✅ 验证通过

发散函数

// 返回never类型(!)的函数——永远不会正常返回
fn panic_if_negative(x: i32) -> i32 {
    if x < 0 {
        panic!("不能为负数!got {}", x);
    }
    x
}

// 循环也返回never类型
fn forever() -> ! {
    loop {
        // 永远不会返回
    }
}

fn main() {
    let x = 42;
    let y = panic_if_negative(x);
    println!("y = {}", y);
    // panic_if_negative(-1);  // 运行时panic!
}
y = 42

✅ 验证通过

🎮 综合示例:猜数字游戏

use std::io::{self, Write};

fn get_input(prompt: &str) -> String {
    print!("{}", prompt);
    io::stdout().flush().unwrap();
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();
    input.trim().to_string()
}

fn evaluate_guess(secret: i32, guess: i32) -> &'static str {
    if guess < secret {
        "太小了!"
    } else if guess > secret {
        "太大了!"
    } else {
        "猜对了!🎉"
    }
}

fn main() {
    let secret = 42;  // 固定答案,演示用
    println!("🎲 猜数字游戏!");
    println!("我想了一个1-100之间的数字");
    
    let mut attempts = 0;
    
    loop {
        let input = get_input("请输入你的猜测: ");
        
        let guess: i32 = match input.parse() {
            Ok(n) => n,
            Err(_) => {
                println!("请输入有效数字!");
                continue;
            }
        };
        
        attempts += 1;
        let result = evaluate_guess(secret, guess);
        println!("{}", result);
        
        if guess == secret {
            println!("你用了{}次猜对了!", attempts);
            break;
        }
    }
}

📝 练习

练习1:FizzBuzz

编写程序输出1-100:3的倍数输出"Fizz",5的倍数输出"Buzz",15的倍数输出"FizzBuzz",其他输出数字本身。

练习2:斐波那契

编写函数fib(n: u32) -> u64返回第n个斐波那契数,用迭代和递归两种方式实现。

练习3:九九乘法表

用嵌套for循环输出九九乘法表。

练习4:计算器函数

编写calculate(op: char, a: f64, b: f64) -> Option<f64>,支持+、-、*、/运算,除0返回None。

🏆 本课成就

🔒 下一课解锁:所有权与借用 —— Rust最独特也最核心的特性

🔧 函数式编程风格

fn main() {
    // 函数组合模式
    let process = |s: &str| -> String {
        s.split_whitespace()
            .map(|w| w.to_uppercase())
            .filter(|w| w.len() > 2)
            .collect::>()
            .join(" ")
    };
    println!("{}", process("hi hello world rust ok"));
    
    // 柯里化模拟
    fn make_adder(x: i32) -> impl Fn(i32) -> i32 {
        move |y| x + y
    }
    let add5 = make_adder(5);
    println!("5+3 = {}", add5(3));
    
    // 折叠操作
    let nums = vec![1, 2, 3, 4, 5];
    let product: i32 = nums.iter().fold(1, |acc, &x| acc * x);
    println!("5! = {}", product);
    
    // 管道操作
    let result = "hello world rust programming"
        .split_whitespace()
        .map(|w| w.len())
        .filter(|&l| l > 3)
        .sum::();
    println!("长单词字母总数: {}", result);
}
HELLO WORLD RUST 5+3 = 8 5! = 120 长单词字母总数: 18

✅ 验证通过

📐 递归与尾调用

// 普通递归
fn fib_recursive(n: u32) -> u64 {
    match n {
        0 => 0, 1 => 1,
        _ => fib_recursive(n - 1) + fib_recursive(n - 2),
    }
}

// 迭代版本(推荐)
fn fib_iterative(n: u32) -> u64 {
    let mut a = 0u64;
    let mut b = 1u64;
    for _ in 0..n {
        let temp = a + b;
        a = b;
        b = temp;
    }
    a
}

// 累加器递归
fn factorial_tail(n: u64, acc: u64) -> u64 {
    if n <= 1 { acc } else { factorial_tail(n - 1, acc * n) }
}

fn main() {
    println!("fib_iterative(30) = {}", fib_iterative(30));
    println!("fib_iterative(50) = {}", fib_iterative(50));
    println!("10! = {}", factorial_tail(10, 1));
    
    // ⚠️ Rust不保证尾调用优化(TCO)
    // 深度递归可能导致栈溢出
    // 推荐用迭代或显式栈替代
    println!("提示:Rust不保证TCO,深度递归请用迭代");
}
fib_iterative(30) = 832040 fib_iterative(50) = 12586269025 10! = 3628800 提示:Rust不保证TCO,深度递归请用迭代

✅ 验证通过