Skip to content

猜数字游戏 ​

目标:程序在 1 到 100 之间随机取一个整数,循环读取用户猜测,提示"太大/太小",猜中后退出。本课基于一份可运行的完整实现,梳理其中用到的全部知识点。

1. 依赖:引入 rand ​

随机数来自 crates.io 上最常用的 rand 库,在 Cargo.toml 中声明即可:

toml
[package]
name = "lesson_0002"
version = "0.1.0"
edition.workspace = true

[dependencies]
rand = "0.10.2"
  • "0.10.2" 遵循语义化版本,cargo 据此下载依赖并锁定到 Cargo.lock。
  • 声明等价于命令 cargo add rand,无需手动编辑文件。

2. 完整实现(注释版) ​

rust
// 引入第三方 crate rand 的 RngExt trait:random_range 方法由它提供。
// 规则:调用某 trait 的方法前,该 trait 必须在当前作用域内。
use rand::RngExt;
// 一次引入标准库的多个项:{} 内为嵌套路径写法,等价于两行独立的 use。
use std::{cmp::Ordering, io};

fn main() {
    println!("猜数字游戏!请输入你的猜测:");

    // 生成随机答案:rng() 获取随机数生成器,random_range(1..=100) 取 [1, 100] 区间内的整数(含两端)。
    // secret_number 未加 mut:猜数字过程中答案不可变,符合默认不可变约定。
    // #region answer
    let secret_number = rand::rng().random_range(1..=100);
    // #endregion answer

    let mut guess_times = 0;

    loop {
        // 创建可变的空字符串:read_line 需要向其中写入内容,因此必须声明 mut。
        // #region read
        let mut guess = String::new();
        io::stdin().read_line(&mut guess).expect("🔴 读取输入失败!");
        // #endregion read

        // 遮蔽(shadowing):重新声明同名变量 guess,类型从 String 变为 u32。
        // trim() 去掉首尾空白(read_line 会带入换行符);
        // parse() 把字符串解析为数字,目标类型由左侧的 u32 标注决定;
        // parse 同样返回 Result,expect 在解析失败(如输入非数字)时终止程序。
        // #region convert
        let guess: u32 = guess.trim().parse().expect("🔴 请输入数字!");
        // #endregion convert

        // match 表达式:对 cmp 的结果逐一匹配分支,必须覆盖所有可能(穷尽性)。
        // cmp 比较两个值,返回 Ordering 枚举:Less(小)/ Greater(大)/ Equal(相等)。
        // &secret_number 以引用方式传入,不转移所有权(详见后续所有权课程)。
        // #region compare
        match guess.cmp(&secret_number) {
            Ordering::Less => {
                guess_times += 1;
                println!("🔴 太小了!");
            }
            Ordering::Greater => {
                guess_times += 1;
                println!("🔴 太大了!");
            }
            Ordering::Equal => {
                println!("🎉 猜对了!");
                println!("猜了 {} 次", guess_times);
                break; // 猜中后退出 loop,程序结束
            }
        }
        // #endregion compare
    }
}

3. 知识点清单 ​

组织与引入

知识点说明
use 与路径把其他模块/crate 的项引入当前作用域
嵌套路径 std::{cmp::Ordering, io}一次引入同前缀的多个项,等价于两行 use
trait 在作用域内random_range 由 RngExt trait 提供;trait 不引入就无法调用其方法
fn main()binary crate 的入口函数,程序从此开始执行

依赖管理

知识点说明
[dependencies]声明第三方依赖与版本要求
语义化版本 + Cargo.lock"0.10.2" 是版本要求,实际版本锁定在 lock 文件中

读取输入

知识点说明
String::new()创建新的空字符串
mut变量默认不可变;read_line 要写入,必须声明可变
io::stdin().read_line(&mut guess)从标准输入读一行,追加写入 guess,包含末尾换行符
&mut以可变方式借用,不取得所有权(后续所有权课程展开)
Result 与 expectread_line 返回 Result;expect 在失败时终止程序并显示消息

类型转换

知识点说明
trim()去掉首尾空白,处理 read_line 带入的换行符
parse() + 类型标注 u32字符串解析为数字,目标类型由左侧标注决定;返回 Result
遮蔽(shadowing)let guess: u32 = guess... 重新声明同名变量,类型可从 String 变为 u32

随机数

知识点说明
rand::rng()获取当前线程的随机数生成器
random_range(1..=100)在指定范围内取随机值;..= 表示包含两端

控制流

知识点说明
loop / break无限循环;break 退出循环
match模式匹配表达式,分支必须穷尽所有可能
cmp 与 Ordering比较两个值,返回 Less / Greater / Equal 枚举
&secret_number以引用传入,供 cmp 读取而不取得所有权

4. 参考 ​