Rust专项——猜数字游戏实战:综合运用所学知识
·

引言
猜数字游戏是学习编程的经典项目,它综合运用了变量、数据类型、输入输出、控制流、循环、错误处理等核心知识点。通过实现一个完整的猜数字游戏,你可以将之前学到的Rust知识融会贯通。
本文将带你从零开始构建一个完整的猜数字游戏,包括:
- 基础版本:最简单的实现
- 增强版本:添加次数限制和统计
- 完整版本:错误处理、输入验证、难度选择
- 高级版本:使用随机数、优化用户体验
通过本文的学习,你将能够:
- 理解Rust的输入输出机制
- 掌握随机数生成的方法
- 学会处理用户输入和错误
- 综合运用循环、条件判断等控制流
- 写出健壮、用户友好的Rust程序
1. 项目准备
1.1 创建项目
首先,使用Cargo创建新项目:
cargo new guessing_game
cd guessing_game
1.2 添加依赖(用于生成随机数)
编辑 Cargo.toml 文件,添加 rand 依赖:
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"
[dependencies]
rand = "0.8"
2. 基础版本:最简单的猜数字游戏
2.1 版本1:固定数字,基本循环
这是最基础的版本,用于理解游戏逻辑:
use std::io;
fn main() {
println!("=== 猜数字游戏 ===");
println!("我已经想好了一个1到100之间的数字,来猜猜看!");
let secret_number = 42; // 固定数字,便于测试
let mut attempts = 0;
loop {
attempts += 1;
println!("\n尝试第 {} 次", attempts);
print!("请输入你的猜测: ");
// 刷新输出缓冲区,确保提示信息立即显示
io::Write::flush(&mut io::stdout()).expect("刷新失败");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("读取输入失败");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("请输入一个有效的数字!");
attempts -= 1; // 不计入尝试次数
continue;
}
};
println!("你猜的是: {}", guess);
if guess == secret_number {
println!("🎉 恭喜!你猜对了!");
println!("你用了 {} 次尝试", attempts);
break;
} else if guess < secret_number {
println!("太小了!");
} else {
println!("太大了!");
}
}
}
代码解析:
- 使用
loop创建游戏主循环 io::stdin().read_line()读取用户输入trim().parse()去除换行符并转换为数字match表达式处理解析可能失败的情况break在猜对时退出循环
2.2 版本2:添加次数限制
use std::io;
fn main() {
println!("=== 猜数字游戏 ===");
println!("我已经想好了一个1到100之间的数字,来猜猜看!");
println!("你有7次机会!");
let secret_number = 42;
let max_attempts = 7;
let mut attempts = 0;
loop {
attempts += 1;
let remaining = max_attempts - attempts + 1;
println!("\n尝试第 {} 次(还剩 {} 次机会)", attempts, remaining);
print!("请输入你的猜测: ");
io::Write::flush(&mut io::stdout()).expect("刷新失败");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("读取输入失败");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("请输入一个有效的数字!");
attempts -= 1;
continue;
}
};
if guess == secret_number {
println!("🎉 恭喜!你猜对了!");
println!("你用了 {} 次尝试", attempts);
break;
} else if attempts >= max_attempts {
println!("❌ 游戏结束!你已经用完了所有机会。");
println!("答案是: {}", secret_number);
break;
} else if guess < secret_number {
println!("太小了!");
} else {
println!("太大了!");
}
}
}
3. 增强版本:添加随机数和更好体验
3.1 版本3:使用随机数生成器
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("=== 猜数字游戏 ===");
// 生成1到100之间的随机数
let secret_number = rand::thread_rng().gen_range(1..=100);
println!("我已经想好了一个1到100之间的数字,来猜猜看!");
println!("(提示:秘密数字是 {} - 仅用于调试)", secret_number);
let mut attempts = 0;
const MAX_ATTEMPTS: u32 = 7;
loop {
attempts += 1;
let remaining = MAX_ATTEMPTS - attempts + 1;
if remaining == 0 {
println!("\n❌ 游戏结束!你已经用完了所有机会。");
println!("答案是: {}", secret_number);
break;
}
println!("\n尝试第 {} 次(还剩 {} 次机会)", attempts, remaining);
print!("请输入你的猜测 (1-100): ");
io::Write::flush(&mut io::stdout()).expect("刷新失败");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("读取输入失败");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("⚠️ 请输入一个有效的数字!");
attempts -= 1;
continue;
}
};
// 验证输入范围
if guess < 1 || guess > 100 {
println!("⚠️ 请输入1到100之间的数字!");
attempts -= 1;
continue;
}
println!("你猜的是: {}", guess);
// 使用 match 和 Ordering
match guess.cmp(&secret_number) {
Ordering::Less => {
println!("📉 太小了!");
}
Ordering::Greater => {
println!("📈 太大了!");
}
Ordering::Equal => {
println!("🎉 恭喜!你猜对了!");
println!("你用了 {} 次尝试", attempts);
// 根据尝试次数给予不同评价
match attempts {
1 => println!("🌟 太厉害了!一次就猜中!"),
2..=3 => println!("⭐ 很棒!用很少的次数就猜中了!"),
4..=5 => println!("👍 不错!猜中了!"),
_ => println!("🎯 虽然用了不少次数,但还是猜中了!"),
}
break;
}
}
}
}
新增特性:
- 使用
rand::thread_rng().gen_range(1..=100)生成随机数 - 使用
Ordering枚举进行更优雅的比较 - 添加输入范围验证(1-100)
- 根据尝试次数给出不同评价
3.2 版本4:添加难度选择
use std::io;
use std::cmp::Ordering;
use rand::Rng;
struct GameConfig {
min: u32,
max: u32,
max_attempts: u32,
}
impl GameConfig {
fn easy() -> Self {
Self {
min: 1,
max: 50,
max_attempts: 8,
}
}
fn medium() -> Self {
Self {
min: 1,
max: 100,
max_attempts: 7,
}
}
fn hard() -> Self {
Self {
min: 1,
max: 200,
max_attempts: 6,
}
}
}
fn select_difficulty() -> GameConfig {
loop {
println!("\n=== 选择难度 ===");
println!("1. 简单 (1-50, 8次机会)");
println!("2. 中等 (1-100, 7次机会)");
println!("3. 困难 (1-200, 6次机会)");
print!("请选择 (1-3): ");
io::Write::flush(&mut io::stdout()).expect("刷新失败");
let mut choice = String::new();
io::stdin()
.read_line(&mut choice)
.expect("读取输入失败");
match choice.trim() {
"1" => {
println!("你选择了:简单难度");
return GameConfig::easy();
}
"2" => {
println!("你选择了:中等难度");
return GameConfig::medium();
}
"3" => {
println!("你选择了:困难难度");
return GameConfig::hard();
}
_ => {
println!("无效选择,请输入 1、2 或 3");
}
}
}
}
fn main() {
println!("=== 猜数字游戏 ===");
let config = select_difficulty();
let secret_number = rand::thread_rng().gen_range(config.min..=config.max);
println!("\n我已经想好了一个{}到{}之间的数字,来猜猜看!",
config.min, config.max);
println!("你有 {} 次机会!", config.max_attempts);
let mut attempts = 0;
let mut min_guess = config.min;
let mut max_guess = config.max;
loop {
attempts += 1;
let remaining = config.max_attempts - attempts + 1;
if remaining == 0 {
println!("\n❌ 游戏结束!你已经用完了所有机会。");
println!("答案是: {}", secret_number);
break;
}
println!("\n=== 尝试第 {} 次(还剩 {} 次机会) ===", attempts, remaining);
println!("当前范围提示: {} - {}", min_guess, max_guess);
print!("请输入你的猜测: ");
io::Write::flush(&mut io::stdout()).expect("刷新失败");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("读取输入失败");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("⚠️ 请输入一个有效的数字!");
attempts -= 1;
continue;
}
};
if guess < config.min || guess > config.max {
println!("⚠️ 请输入{}到{}之间的数字!", config.min, config.max);
attempts -= 1;
continue;
}
match guess.cmp(&secret_number) {
Ordering::Less => {
println!("📉 太小了!");
min_guess = guess.max(min_guess); // 更新最小值提示
}
Ordering::Greater => {
println!("📈 太大了!");
max_guess = guess.min(max_guess); // 更新最大值提示
}
Ordering::Equal => {
println!("\n🎉🎉🎉 恭喜!你猜对了!🎉🎉🎉");
println!("秘密数字是: {}", secret_number);
println!("你用了 {} 次尝试", attempts);
// 评价系统
let score = (config.max_attempts - attempts + 1) * 100 / config.max_attempts;
println!("得分: {} 分", score);
match attempts {
1 => println!("🌟 传奇!一次就猜中!你是神吗?"),
2..=3 => println!("⭐ 卓越!你的直觉太准了!"),
4..=5 => println!("👍 优秀!很棒的表现!"),
_ => println!("🎯 完成了挑战!继续努力!"),
}
break;
}
}
}
}
新增特性:
- 使用结构体
GameConfig配置游戏参数 - 难度选择功能
- 动态范围提示(显示当前可能的范围)
- 评分系统
4. 完整版本:完整的错误处理和用户体验
4.1 版本5:完整的游戏实现
use std::io;
use std::cmp::Ordering;
use rand::Rng;
// 游戏配置结构体
struct GameConfig {
min: u32,
max: u32,
max_attempts: u32,
difficulty: String,
}
impl GameConfig {
fn new(min: u32, max: u32, max_attempts: u32, difficulty: &str) -> Self {
Self {
min,
max,
max_attempts,
difficulty: difficulty.to_string(),
}
}
fn easy() -> Self {
Self::new(1, 50, 8, "简单")
}
fn medium() -> Self {
Self::new(1, 100, 7, "中等")
}
fn hard() -> Self {
Self::new(1, 200, 6, "困难")
}
fn expert() -> Self {
Self::new(1, 500, 5, "专家")
}
}
// 游戏统计
struct GameStats {
attempts: u32,
min_range: u32,
max_range: u32,
guesses: Vec<u32>,
}
impl GameStats {
fn new(config: &GameConfig) -> Self {
Self {
attempts: 0,
min_range: config.min,
max_range: config.max,
guesses: Vec::new(),
}
}
fn add_guess(&mut self, guess: u32, config: &GameConfig) {
self.attempts += 1;
self.guesses.push(guess);
// 根据猜测结果更新范围
if guess < self.max_range {
self.max_range = guess.max(self.min_range);
}
if guess > self.min_range {
self.min_range = guess.min(self.max_range);
}
}
fn get_remaining(&self, config: &GameConfig) -> u32 {
config.max_attempts.saturating_sub(self.attempts)
}
fn show_history(&self) {
if !self.guesses.is_empty() {
print!("历史猜测: ");
for (i, &g) in self.guesses.iter().enumerate() {
print!("{}", g);
if i < self.guesses.len() - 1 {
print!(", ");
}
}
println!();
}
}
}
// 读取用户输入的函数
fn read_user_input(prompt: &str) -> Result<String, io::Error> {
print!("{}", prompt);
io::Write::flush(&mut io::stdout())?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
Ok(input.trim().to_string())
}
// 读取数字输入的函数
fn read_number(prompt: &str, min: u32, max: u32) -> Result<u32, String> {
let input = read_user_input(prompt)
.map_err(|_| "读取输入失败".to_string())?;
let num: u32 = input
.parse()
.map_err(|_| "请输入一个有效的数字!".to_string())?;
if num < min || num > max {
return Err(format!("请输入{}到{}之间的数字!", min, max));
}
Ok(num)
}
// 选择难度
fn select_difficulty() -> GameConfig {
loop {
println!("\n╔════════════════════════════════════╗");
println!("║ 选择游戏难度 ║");
println!("╠════════════════════════════════════╣");
println!("║ 1. 简单 (1-50, 8次机会) ║");
println!("║ 2. 中等 (1-100, 7次机会) ║");
println!("║ 3. 困难 (1-200, 6次机会) ║");
println!("║ 4. 专家 (1-500, 5次机会) ║");
println!("╚════════════════════════════════════╝");
match read_user_input("请选择 (1-4): ") {
Ok(choice) => {
match choice.as_str() {
"1" => {
println!("\n✅ 你选择了:简单难度");
return GameConfig::easy();
}
"2" => {
println!("\n✅ 你选择了:中等难度");
return GameConfig::medium();
}
"3" => {
println!("\n✅ 你选择了:困难难度");
return GameConfig::hard();
}
"4" => {
println!("\n✅ 你选择了:专家难度");
return GameConfig::expert();
}
_ => {
println!("❌ 无效选择,请输入 1、2、3 或 4");
}
}
}
Err(_) => {
println!("❌ 读取输入失败,请重试");
}
}
}
}
// 显示游戏结果
fn show_result(secret_number: u32, stats: &GameStats, config: &GameConfig) {
println!("\n╔════════════════════════════════════╗");
println!("║ 🎉 游戏结果 🎉 ║");
println!("╠════════════════════════════════════╣");
println!("║ 秘密数字: {:>23} ║", secret_number);
println!("║ 使用次数: {:>23} ║", stats.attempts);
println!("║ 难度等级: {:>23} ║", config.difficulty);
let score = if stats.attempts <= config.max_attempts {
((config.max_attempts - stats.attempts + 1) * 100) / config.max_attempts
} else {
0
};
println!("║ 得分: {:>25} ║", score);
println!("╚════════════════════════════════════╝");
// 评价
match stats.attempts {
1 => println!("\n🌟 传奇!一次就猜中!你是神吗?"),
2..=3 => println!("\n⭐ 卓越!你的直觉太准了!"),
4..=5 => println!("\n👍 优秀!很棒的表现!"),
_ if stats.attempts <= config.max_attempts => {
println!("\n🎯 完成了挑战!继续努力!")
}
_ => println!("\n💪 不要气馁,再试一次!"),
}
}
// 主游戏循环
fn play_game(config: GameConfig) {
let secret_number = rand::thread_rng().gen_range(config.min..=config.max);
let mut stats = GameStats::new(&config);
println!("\n╔════════════════════════════════════╗");
println!("║ 游戏开始! ║");
println!("╠════════════════════════════════════╣");
println!("║ 范围: {} - {}", config.min, config.max);
println!("║ 机会: {} 次", config.max_attempts);
println!("╚════════════════════════════════════╝");
loop {
let remaining = stats.get_remaining(&config);
if remaining == 0 {
println!("\n❌ 游戏结束!你已经用完了所有机会。");
show_result(secret_number, &stats, &config);
break;
}
println!("\n═══════════════════════════════════════");
println!("尝试第 {} 次(还剩 {} 次机会)", stats.attempts + 1, remaining);
println!("当前范围提示: {} - {}", stats.min_range, stats.max_range);
stats.show_history();
match read_number("请输入你的猜测: ", config.min, config.max) {
Ok(guess) => {
println!("你猜的是: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => {
println!("📉 太小了!");
stats.add_guess(guess, &config);
}
Ordering::Greater => {
println!("📈 太大了!");
stats.add_guess(guess, &config);
}
Ordering::Equal => {
stats.attempts += 1;
stats.guesses.push(guess);
println!("\n🎉🎉🎉 恭喜!你猜对了!🎉🎉🎉");
show_result(secret_number, &stats, &config);
break;
}
}
}
Err(err) => {
println!("⚠️ {}", err);
// 不增加尝试次数
}
}
}
}
// 询问是否继续游戏
fn ask_play_again() -> bool {
loop {
match read_user_input("\n是否再玩一次?(y/n): ") {
Ok(input) => {
match input.to_lowercase().as_str() {
"y" | "yes" | "是" => return true,
"n" | "no" | "否" => return false,
_ => println!("请输入 y 或 n"),
}
}
Err(_) => {
println!("读取输入失败");
return false;
}
}
}
}
fn main() {
println!("╔════════════════════════════════════╗");
println!("║ 🎮 猜数字游戏 🎮 ║");
println!("║ ║");
println!("║ 欢迎来到猜数字游戏! ║");
println!("║ 我会想一个数字,你来猜! ║");
println!("╚════════════════════════════════════╝");
loop {
let config = select_difficulty();
play_game(config);
if !ask_play_again() {
println!("\n👋 感谢游玩!再见!");
break;
}
}
}
需要加上库的使用
[package]
name = “hello_world_new”
version = “0.1.0”
edition = “2021”
[dependencies]
rand = “0.8.5” # 版本号可根据实际需求调整,也可用最新稳定版


完整功能清单:
- ✅ 难度选择(简单、中等、困难、专家)
- ✅ 随机数生成
- ✅ 输入验证和错误处理
- ✅ 范围提示(动态更新)
- ✅ 猜测历史记录
- ✅ 尝试次数限制
- ✅ 评分系统
- ✅ 再次游戏功能
- ✅ 友好的用户界面
5. 代码解析与知识点
5.1 关键Rust特性应用
1. 结构体和方法(初步了解)
struct GameConfig {
min: u32,
max: u32,
max_attempts: u32,
}
impl GameConfig {
fn easy() -> Self {
// 关联函数
}
}
2. Result和错误处理
fn read_number(...) -> Result<u32, String> {
// 使用Result处理可能的错误
Ok(value) // 成功
Err(message) // 失败
}
3. 模式匹配
match guess.cmp(&secret_number) {
Ordering::Less => { ... }
Ordering::Greater => { ... }
Ordering::Equal => { ... }
}
4. 向量(Vec)
let mut guesses: Vec<u32> = Vec::new();
guesses.push(guess); // 添加元素
5.2 随机数生成详解
use rand::Rng;
// 生成1到100之间的随机数(包含边界)
let secret_number = rand::thread_rng().gen_range(1..=100);
// 生成1到100之间的随机数(不包含100)
let secret_number = rand::thread_rng().gen_range(1..100);
5.3 输入输出详解
use std::io;
// 读取一行输入
let mut input = String::new();
io::stdin()
.read_line(&mut input) // 读取到String
.expect("读取失败");
// 打印(不换行)
print!("请输入: ");
io::Write::flush(&mut io::stdout()); // 立即显示
// 打印(换行)
println!("结果: {}", value);
5.4 字符串处理
let input = "42\n";
let trimmed = input.trim(); // 去除首尾空白字符 -> "42"
let number: u32 = trimmed.parse().unwrap(); // 字符串转数字
6. 常见问题与解决方案
问题1:输入时程序卡住
原因:没有刷新输出缓冲区
解决:
print!("请输入: ");
io::Write::flush(&mut io::stdout()).expect("刷新失败");
问题2:无法解析输入为数字
原因:输入的字符串包含换行符或空白字符
解决:
let guess: u32 = guess.trim().parse()?;
问题3:数字超出范围
解决:添加范围验证
if guess < min || guess > max {
println!("数字超出范围!");
continue;
}
7. 扩展练习
练习1:添加计时功能
记录玩家完成游戏所用的时间。
练习2:保存历史记录
将每次游戏的结果保存到文件中。
练习3:多人模式
实现两个玩家轮流猜测的功能。
练习4:提示系统
添加"很接近"的提示(如相差5以内)。
练习5:排行榜
根据得分和尝试次数创建排行榜。
8. 总结
核心知识点回顾
- 循环控制:使用
loop、break、continue - 条件判断:使用
if、match、Ordering - 输入输出:
io::stdin()、read_line()、print!、println! - 错误处理:
Result、match、expect - 随机数:
rand::thread_rng().gen_range() - 数据结构:
Vec、结构体、枚举
项目收获
- ✅ 综合应用:将多个知识点融会贯通
- ✅ 错误处理:学会处理用户输入错误
- ✅ 用户体验:关注程序的可用性
- ✅ 代码组织:使用函数和结构体组织代码
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)