Rust 学习笔记 10:项目实战一:猜数字

“Programming is not about typing, it’s about thinking.”

之前的 9 篇笔记,我们一直在抠语法细节。 今天是圣诞节(假设),我们来点轻松的:用 Rust 写一个猜数字游戏

规则很简单:

  1. 程序生成一个 1~100 的随机数。
  2. 玩家输入猜测。
  3. 程序提示 “大了”、“小了” 或 “猜对了”。
  4. 猜对了游戏结束,否则继续。

1. 引入依赖 Crates

Rust 的标准库很精简,没有内置随机数生成。我们需要引入第三方库 rand。 修改 Cargo.toml

1[dependencies]
2rand = "0.9"

这和 Go 的 go get 不太一样,Rust 更像是 Node.js 的 npm,依赖管理非常现代化。

2. 获取用户输入

1use std::io;
2
3let mut guess = String::new(); // 创建可变空字符串
4
5io::stdin()
6    .read_line(&mut guess) // 传可变引用进去修改
7    .expect("Failed to read line"); // 处理 Result::Err

注意那个 read_line 返回的是 io::Result 枚举。如果读取失败,它会返回 Errexpect 方法会帮你 panic 并打印错误信息。在 Rust 中,忽略返回值是会被警告的。

3. 生成随机数

use rand::{rng, Rng};

let secret_number = rng().random_range(1..=100);

1..=100 是 Range 语法,表示 [1, 100] (包含 100)。

4. 字符串转数字与错误处理

用户输入的是字符串 “50\n”,我们需要把它转换成数字。

// Shadowing (变量遮蔽) 再次登场!
let guess: u32 = match guess.trim().parse() {
    Ok(num) => num,
    Err(_) => continue, // 如果输入的不是数字,跳过本次循环
};

这里展示了 Rust 强大的错误处理模式。Go 通常是 if err != nil,Rust 是用 match 匹配 Result 枚举。

5. 比较与 Match

std::cmp::Ordering 是一个枚举,有三个变体:Less, Greater, Equal

use std::cmp::Ordering;

match guess.cmp(&secret_number) {
    Ordering::Less => println!("Too small!"),
    Ordering::Greater => println!("Too big!"),
    Ordering::Equal => {
        println!("You win!");
        break; // 退出 loop 循环
    }
}

6. 小结

第十篇笔记,我们完成了一个小里程碑。

在这个 40 行左右的小程序里,我们实际上使用了:

  • 变量与可变性 (let mut)
  • 关联函数 (String::new)
  • 引用 (&mut guess)
  • Result 枚举与错误处理 (expect, match)
  • 外部 Crates (rand)
  • Match 模式匹配 (cmp)
  • 循环与控制流 (loop, break, continue)

这下是不是感觉之前的知识都串起来了?

下一篇,我们将进入 Rust 的另一个深水区:包、Crate 与模块系统。这曾经让无数 Rust 初学者(包括我)在文件引用上痛不欲生。


练习题

  1. 修改游戏,限制玩家只能猜 5 次,5 次没猜对则游戏失败。
  2. 骚操作挑战:不使用 rand 库,尝试用 SystemTime 获取当前时间戳作为种子生成伪随机数(了解一下线性同余法)。

思考题

在 Go 中,我们习惯把所有代码扔在 main 包里。Rust 的 cratemodule 设计哲学是什么?它和 Java 的 package 或 Go 的 package 有什么本质区别?


本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读