尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

【Rust自学】2.3. 猜数游戏Pt.3 输入数与随机数的对比

【Rust自学】2.3. 猜数游戏Pt.3 输入数与随机数的对比
📅 发布时间:2026/7/23 19:08:08

2.3 猜数游戏Pt.3 输入数与随机数的对比

2.3.0 本篇知识点

在本篇中,你将学到:
-match的用法
- 遮蔽(shadowing)
- 类型转换
-Ordering类型

2.3.1 游戏目标

  • 生成一个 1 到 100 间的随机数
  • 提示玩家输入一个猜测
  • 猜完之后,程序会提示猜测是太大了还是太小了(本篇会涉及)
  • 如果猜测正确,那么打印一个庆祝信息,程序退出

2.3.2 代码实现

这是截止到 2.2 猜数游戏Pt.2 生成随机数 所写出来的代码:

use std::io; use rand::Rng; fn main() { let range_number = rand::thread_rng().gen_range(1..101); println!("Number Guessing Game"); println!("Guess a number"); let mut guess = String::new(); io::stdin().read_line(&mut guess).expect("Could not read the line"); println!("The number you guessed is:{}", guess); println!("The secret number is: {}", range_number); }

Step 1:数据类型的转换

由代码可知,guess是字符串,而range_number是整数。这两个变量类型不同,不能直接比较。我们需要把字符串转换成整数——这里会使用u32(无符号 32 位整数)。range_number最终被推断成哪一种整数类型,会在下文写出比较代码后更清楚。

let guess: u32 = guess.trim().parse().expect("Please enter a number");
  • let guess: u32:声明一个名为guess、类型为u32(无符号 32 位整数,也就是不能表示负数)的变量。
    但这里有一个问题:在之前的代码中(let mut guess = String::new();)已经声明了一个叫做guess的变量,不会报错吗?答案是不会,因为 Rust 允许用同名的新变量遮蔽旧变量。这叫做遮蔽(shadowing)(当一个变量、函数或类型的名称在当前作用域中被重新定义时,会隐藏外部作用域中同名的变量、函数或类型)。它允许代码复用同一个变量名,而无需声明新的变量。这个特性会在 3.1 变量与可变性 仔细介绍。

这里可以举一个例子:

fn main() { let a = 1; println!("{}", a); let a = "one"; println!("{}", a); }

这么做程序不会报错,并且会打印出:

1 one

当程序执行到第一个let绑定处时,a被赋值为1,所以紧接着的println!打印出的是1;当第二个let复用名字a时,它会用"one"遮蔽旧值,所以下一行打印的就是one。这就是遮蔽。

  • =:赋值
  • guess.trim():这里的guess指的是旧的guess,类型为字符串,内容是用户输入。因为read_line()也会把用户的回车记录进去,所以需要使用.trim()。.trim()的作用是去掉字符串前后的空格和换行,类似于 Python 中的.strip()。
  • .parse():它可以把字符串解析为某种数值类型。用户的正常输入会是 1 到 100 间的数,这个数可以放进i32、u32或i64等类型。那么解析后到底是哪种类型呢?你得告诉 Rust 你要哪种类型,所以在声明变量时才要显式指定为u32(类似于 Python 中的静态类型标注,在变量名后面加上:desired_type)。
    当然,转换有可能会失败。比如说输入xyz,就没法解析成整数。Rust 足够聪明,让.parse()返回一个Result类型(在 2.1 猜数游戏Pt.1 一次猜测 中讲到过)。这种枚举有两个变体:Ok和Err。如果转换成功,枚举就会返回Ok和转换后的结果;如果失败,就会返回Err和失败原因。
  • .expect():它是Result类型上的一个方法,与.parse()的返回值类型相同。如果解析失败,.parse()就会返回Err,.expect()会立即触发panic!,终止当前程序,并打印expect中的错误信息。反之,.parse()就会返回Ok,.expect()会把附加的值返回出来,也就是把转换好的数字赋给guess。

Step 2:数字的比较

在成功转换数据类型后,我们就可以比较这两个数字了。
先在代码开头导入类型:

use std::cmp::Ordering;

这段代码表示从std标准库里引入一个叫做Ordering的类型。Ordering是一个枚举,它有三个变体(可以把它理解为三个可能的值):Ordering::Less、Ordering::Greater和Ordering::Equal,分别表示小于、大于和等于。

再在main里写下对比代码:

match guess.cmp(&range_number) { Ordering::Less => println!("Too small"), Ordering::Greater => println!("Too big"), Ordering::Equal => println!("You win"), }
  • guess.cmp(&range_number):guess上有一个方法叫.cmp()(cmp是 compare 的缩写)。它会比较点号前面的值和括号里的值。这里点号前面的值是guess,括号里的值是对range_number的引用(&是取地址符,代表引用)。.cmp()的返回值类型是Ordering,也就是上文导入的类型。

这里还涉及到了 Rust 的类型推断。这里有两张 IDE 截图,一张是还没写这段match表达式时,一张是写了之后。注意看let range_number = rand::thread_rng().gen_range(1..101);这一行(第 5 行):


可以看到,没有写match表达式时,IDE 提示range_number的类型是i32;写了match之后,IDE 提示range_number的类型是u32。这是为什么呢?因为guess.cmp(&range_number)进行了比较,虽然range_number没有被显式标注类型,但guess已经被显式定义为u32。得益于 Rust 强大的基于上下文的类型推断,guess.cmp(&range_number)的需求会让range_number被推断为u32。而没有match时,因为 Rust 默认的整数类型是i32,且没有任何其他约束要求range_number是别的类型,所以编译器会推断为i32。

  • match:Rust 的模式匹配表达式。它让我们可以根据.cmp()返回的Ordering枚举值来决定下一步操作。一个match表达式由多个分支(也叫臂,英文是 arm)组成。每个分支都包含一个匹配模式(用来匹配输入值的条件)和一个要执行的代码块(模式匹配成功时运行的代码)。如果match后面的值(在这个程序中就是guess.cmp(&range_number))匹配上了某个分支,程序就会执行这个分支下的代码。

在这个程序中,Ordering::Less、Ordering::Greater和Ordering::Equal就是匹配模式,println!("Too small")、println!("Too big")和println!("You win")就是对应的代码块。举个例子,如果guess等于range_number,.cmp()就会返回Ordering::Equal,match找到与之匹配的第三个分支,然后执行这个分支的代码块,也就是println!("You win")。

match会从上到下检查分支。在这个程序里,就是先检查Ordering::Less,再检查Ordering::Greater,最后检查Ordering::Equal。

我们会在 6.3 控制流运算符-match 中更详细地讲解match。

2.3.3 代码效果

以下是截至目前的完整代码:

use std::io; use rand::Rng; use std::cmp::Ordering; fn main() { let range_number = rand::thread_rng().gen_range(1..101); println!("Number Guessing Game"); println!("Guess a number"); let mut guess = String::new(); io::stdin().read_line(&mut guess).expect("Could not read the line"); let guess: u32 = guess.trim().parse().expect("Please enter a number"); println!("The number you guessed is:{}", guess); match guess.cmp(&range_number) { Ordering::Less => println!("Too small"), Ordering::Greater => println!("Too big"), Ordering::Equal => println!("You win"), } println!("The secret number is: {}", range_number); }

效果如下(每次运行的神秘数字都会不同;这里猜测10偏小):

Number Guessing Game Guess a number 10 The number you guessed is:10 Too small The secret number is: 48

相关新闻

  • [AG-UI详解-05]如何构建一个兼容AG-UI协议的客户端
  • INT4 通俗完整讲解
  • Hercules微控制器ECC安全机制:从原理到实战的嵌入式数据保护

最新新闻

  • 【UE4】Generate Visual Studio Project Files sln生成失败 Failed to generate project files
  • 灰狼算法改进与条件重初始化在数字信号去噪中的应用
  • LLM/RAG评估工具链:DeepEval+GroUSE+可解释检索解析
  • 石家庄奢侈品回收避坑指南四大套路拆解教你守住钱包 - 讯息早知道
  • CAN控制器初始化与消息对象配置:从原理到实战的嵌入式通信指南
  • 电商AI客服系统实战:向量知识库与大模型API混合架构

日新闻

  • 亨得利盐城维修点在哪里?手表维修保养地址指南**公示(2026年7月最新) - 亨得利官方
  • 提升.NET API安全性:Boxed.AspNetCore.Swagger认证授权最佳实践
  • 帝舵佛山**网点地址更新:2026年7月售后热线电话与服务客户指南 - 帝舵中国官方服务中心

周新闻

  • SaaS软件行业GEO实践:AI搜索时代的品牌可见性与获客新路径
  • 什么是PCTFE?医药高端包装的“防潮王牌“材料
  • 【JVM调优实战】16-可视化利器-JConsole-VisualVM-JMC

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号