Course Builder个人学习工作台 · 本地模式
Rust:从所有权到可测试的命令行工具

02|变量、函数与控制流:把规则写成计算

目标:写出接收明确类型、返回计算结果的函数,并用条件与循环组合它。

TextLab 需要根据数字决定显示内容,例如把较长文本标记为“long”。先用数字练习,避免在学习语法时同时处理文件和内存问题。

let 建立绑定,默认不能重新赋值;需要更新计数器时写 let mut。类型常能从上下文推断,但函数参数与返回值需要明确写出。这里的 usize 是与目标平台指针宽度一致的无符号整数,标准库用它表示长度和索引。不要把所有业务数字都选成 usize:可能为负数的温度应使用合适的有符号类型。

Rust 区分语句与表达式。函数最后一个没有分号的表达式提供返回值;if 也能产生值,两个分支必须给出兼容类型。分号并不是可以随意添加的装饰。

一个完整的数值实验

创建 examples/values.rs:

fn double(value: usize) -> usize {
    value * 2
}

fn main() {
    let limit: usize = 5;
    let mut total = 0;
    for value in 1..=3 {
        total += double(value);
    }
    let label = if total >= limit { "long" } else { "short" };
    println!("total={total} label={label}");
}

运行前先预测:循环执行几次,double 返回的三个值是什么?

cargo run --quiet --example values

预期输出:

total=12 label=long

1..=3 包含右端点,依次产生 1、2、3;1..3 不包含 3。+= 累加 2、4、6。if 比较 12 与 5,选择字符串字面量 long。格式字符串里的 {total}、{label} 把值插入输出中。--example values 让 Cargo 运行指定实验,而不是 src/main.rs。

函数只负责计算,main 负责展示。这种分工会一直延续到最终项目:统计逻辑不必知道输出要去终端还是测试断言。

只改变一个边界

  1. 把 1..=3 改成 1..3。
  2. 再运行,预期变为 total=6 label=long。
  3. 把 limit 改成 7,预期变为 total=6 label=short。
  4. 恢复主示例,检查每次变化是否只来自你刚修改的条件。

独立练习:写 remaining(limit: usize, used: usize) -> usize。当 used 达到或超过 limit 时返回 0,否则返回差值。不要直接无条件做无符号减法。用 assert_eq! 检查三个例子;这个宏在两边不相等时使程序失败,相等时不打印内容。

完整参考实现

可暂时完整替换 examples/values.rs:

fn remaining(limit: usize, used: usize) -> usize {
    if used >= limit { 0 } else { limit - used }
}

fn main() {
    assert_eq!(remaining(5, 2), 3);
    assert_eq!(remaining(5, 5), 0);
    assert_eq!(remaining(5, 8), 0);
    println!("remaining checks passed");
}

运行同一命令,应输出 remaining checks passed。相等和超过上限都是有效输入,不能只测试正常减法。

如果返回类型报 expected usize, found (),先检查函数末尾是否多了分号;() 是单元类型,常表示没有有意义的返回值。如果修改 total 时提示不能赋值,检查绑定是否有 mut。不要为了消除错误给所有变量都添加 mut,只给真正发生更新的绑定使用它。

本课新增 examples/values.rs,其余文件保持第 1 课状态。

参考资料