用Rust写个猜数字的游戏(详解)
我的学习总结
简单输入
- 建项目,使用cargo的new命令,创建一个guess_number目录
cargo new guess_number cd guess* code .
2. 构造项目
cargo build
3. 处理用户输入
use std::io; fn main() { println!("---猜数字游戏---"); println!("请输入你猜的数字: "); //生成一个String类型的字符串 let mut guess=String::new(); io::stdin().read_line(&mut guess).expect("输入错误\n"); println!("你输入的数字是: {}",guess); }
解析:
- println! :表示输出的一个宏括号里填上要输出的内容
- let mut 变量 :表示生成一个可变的变量,mut表示可变(mutable),如果没有加 mut,则表示变量是只读的,无法修改
- String::new() :生成一个空的字符串,表示创建一个变量,用于以后的输出
- io::stdin() :表示要进行io读取,即要从缓冲区读取内容,主要要在前面加上 use std::io ,表示加入io这个空间。
- read_Line(&mut guess) :表示将要读取一行,中间的内容要填写为变量取地址,相当于指针,要读取对象的地址才能修改变量,别忘了加上mut可变的修饰符
- expect() :返回枚举类型,Ok和Err,如果前面的读取出错了,返回Err,则打印括号里的内容,并停止,如果输入正确,返回Ok,什么都不错
- {} :表示将要输出的变量,是一个占位符
- 简单测试
cargo run
生成一个随机的数字
接下来,需要生成一个秘密数字,好让用户来猜。秘密数字应该每次都不同,这样重复玩才不会乏味;范围应该在 1 到 100 之间,这样才不会太困难。Rust 标准库中尚未包含随机数功能。然而,Rust 团队还是提供了一个包含上述功能的 :rand
rand下载地址
导入rand扩展包:
在Cargo.toml文件的下面,添加这样一行信息:(表示我们要下载rand的扩展包的0.8.5版本,当然你可以根据网站的信息来下载最新的)
rand=“0.8.5”
我们来重新构建一下
cargo build
稍微等待一下,就可以根据你填写的版本,下载rand扩展包,此时构建完成之后,Cargo.lock文件里就会生成rand的相关信息配置,此时我们的rand就配置成功了,如果你想修改版本,直接在Cargo.toml里面修改rand的版本号就可以,然后重新执行 cargo build 来构建它。
下面我们来生成一个随机数字:
- 导入rand的Rng
use rand::Rng; //生成一个随机数字 let secret_number=rand::thread_rng().gen_range(1..101);
注意我们生成的随机数字是不变的,所以不用给它声明为mut,后面照抄就可以(以后再讲),注意gen_raneg的括号里面的格式:
1…101;表示生成一个左闭右开的区间: [1,101) ;
1…=101:表示生成一个左闭右闭的区间,[1,101]
- 显示随机数字
use std::io; use rand::Rng; fn main() { println!("---猜数字游戏---"); //生成一个随机数字 let secret_number=rand::thread_rng().gen_range(1..101); println!("请输入你猜的数字: "); //生成一个String类型的字符串 let mut guess=String::new(); io::stdin().read_line(&mut guess).expect("输入错误\n"); println!("你输入的数字是: {}",guess); println!("随机数字是:{}",secret_number); }
cargo run
比较猜测数字与神秘数字
你可能认为,if else可以轻松的解决这个问题,但是在rust里面我们无法使用if else(就我目前而言不知道),我们要了解一个新的东西: macth(匹配)
导入一个叫做cmp的东西
use std::cmp::Ordering; //匹配 guess和secret_number是什么类型 match guess.cmp(&secret_number) { Ordering::Less => println!("Too small.\n"), Ordering::Greater => println!("Too big.\n"), Ordering::Equal => println!("Equal.\n"), }
但是现在我们还不能编译他,会出错,我们先了解以下这个结构:
- 首先我们增加了另一个 use 声明,从标准库引入了一个叫做 std::cmp::Ordering 的类型到作用域中。 Ordering 也是一个枚举,不过它的成员是 Less、Greater 和 Equal。这是比较两个值时可能出现的三种结果。
- 简单来说cmp返回枚举Less,Greate,Equal中的值,
- guess和secret_number如果Less:小于,则打印,最后带一个break
- guess和secret_number如果Equal:相等,则打印,break
- guess和secret_number如果Greate:大于,则打印,break
- 类似于C/C++的switch语句,匹配选择打印
但是我们忘记了一个很重要的东西:
先试着来编译以下:
cargo run
String不是整形,不能和随机生成的数字相比较,类型不匹配,所以我们必须试着转换类型。
shadow隐藏与类型转换
guess 是 String类型
secret_number是i32类型
我们可以使用rust提供的一个新概念:隐藏(shadow)
//shadow隐藏 let guess:u32=guess.trim().parse().expect("转换失败!\n");
简单来说,当我们在下文创建一个同名的变量时,会自动隐藏上一个同名的变量,我们把以前的这个String类型转换为 u32类型。需要显示指定类型。
- trim :会去除字符串开头和结尾的空白字符
- parse:会转换为合适的指定的类型: u32
之后我们的guess就从String变成了 u32类型,同时上一个guess的String类型就会消失
这时我们就用match同时对两个 u32类型的数进行比较了。
注意:match的cmp会自动强制转化两个变量为同一类型:
secret一开始是 i32类型,生成的随机数,是有符号整型,会自动转换为和guess一样的类型: u32
然后就可以比较了,运行如下:
cargo run
循环程序
我们已经完成了这个程序的大部分,猜数字还应该持续的比较下去,直到你猜到了随机数字:使用loop循环来进行游戏重复进行:
类似于 while(1) 注意,它是无限循环,需要指定游戏的退出
loop { println!("请输入你猜的数字: "); //生成一个String类型的字符串 let mut guess=String::new(); io::stdin().read_line(&mut guess).expect("输入错误\n"); //shadow隐藏 let guess:u32=guess.trim().parse().expect("转换错误!\n"); println!("你输入的数字是: {}",guess); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small.\n"), Ordering::Greater => println!("Too big.\n"), Ordering::Equal => break, //游戏结束 } }
注意要在比较时相等的情况下,指定它退出loop循环,即break
别忘了隐藏随机数字,不打印出来随机数字。
运行程序如下:
cargo run
处理无效输入
我们还剩最后一步,我们如果在输入数字时出现了字母或者其他字符该怎么办?
程序就会直接退出,报错
在变量隐藏和强制转换的时候,指定出错误时需要干的事情:即重新读取
//shadow隐藏 let guess:u32=match guess.trim().parse() { Ok(num) => num, Err(_) => continue, };
别忘了parse的返回类型是Result类型,是一个枚举类型,返回Ok,或者Err
- Ok: 正确,则这个数字就是这个数字
- Err : 错误,将 ‘_’ 作为占位符,接着continue要求重复输入
最后我们再来运行一下程序:
cargo run
这样我们就算输入字符也会提示我们重新输入
这样我们的猜数字游戏就完成了
完整代码
use std::io; use rand::Rng; use std::cmp::Ordering; fn main() { println!("---猜数字游戏---"); //生成一个随机数字 let secret_number=rand::thread_rng().gen_range(1..101); loop { println!("请输入你猜的数字: "); //生成一个String类型的字符串 let mut guess=String::new(); io::stdin().read_line(&mut guess).expect("输入错误\n"); //shadow隐藏 let guess:u32=match guess.trim().parse() { Ok(num) => num, Err(_) => continue, }; println!("你输入的数字是: {}",guess); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small.\n"), Ordering::Greater => println!("Too big.\n"), Ordering::Equal => break, //游戏结束 } } }
这一期只是先了解一下rust语言,如果有什么不懂的函数或者其他的东西,其实我也不懂,今后我们将一步步来讲解这些东西
下期预告:常见rust编程概念: 基本变量和标量函数注释
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209720.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)