Rust官方文档中有一个猜数字的游戏,通过这个游戏可以接触到Rust的很多东西,比如变量、方法、异常处理、 流程控制、 使用扩展包等。这篇文章就来一探究竟。
游戏规则:程序生成一个秘密数字,然后玩游戏的人输入猜测数字,程序会反馈猜测数字大了或者小了,然后玩家重新输入一个数字,直到输入的数字等于秘密数字,游戏结束。
为了清晰的带出相关知识点,整片文章会分为四部分:创建项目、处理猜测、生成秘密数字、比较猜测和秘密数字。
创建项目
使用Cargo命令创建项目:
cargo new guessing_game
创建成功后主要关注两个文件:Cargo.toml和src/main.rs。
Cargo.toml是程序配置文件,包括程序名称、版本、作者等信息,默认会从当前环境中获取,可以按照自己的信息进行修改。
main.rs是程序主文件,默认内容是输出hello world,猜数字游戏的代码将写到这里。
处理猜测
处理猜测部分包括猜测的输入输出,先来看代码:
use std::io;
fn main() {
println!("Guess the number!");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {}", guess);
}
这段程序的基本逻辑是:收先定义一个变量,然后接收用户输入,将用户输入存储到变量中,最后输出变量内容。
相关知识点包括:
- 函数定义:关键字fn;函数名称后的(),如果有参数放到这个括号中;方法体用大括号包裹,左大括号与函数名在同一行。
- 变量定义:关键字let;变量默认是不可更改的,如果需要改需要使用mut关键字;String::new函数返回String的一个新实例。
- 输入输出:使用标准库std中的io模块处理控制台输入输出;stdin函数返回std::io::Stdin的一个实例;read_line方法处理用户的输入,并将其赋值到传入的&mut guess;println!是一个宏,可以将内容输出到控制台。
- 引用:&mut guess是一个可变引用,变量guess的引用。
- 异常处理:read_line会返回一个类型为io::Result的值,这个值是一个枚举,Ok代表成功,Err代表出现错误;它还有一个方法expect,如果Result的值是Ok,则返回它持有的值,如果出现错误,expect会导致程序崩溃退出并输出传入的文本;如果没有使用expect编译时会出现警告。
- 占位符:在println!中使用了一个占位符{},它在实际输出时会被对应的参数替换;可以使用多个占位符,按照先后顺序替换对应的参数。
生成秘密数字
这里的“生成秘密数字”是生成一个1-100的随机数,还是先看代码:
use std::io;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {}", guess);
}
这里引用了一个随机数扩展包,这些包中的库默认情况下不会像std一样自动加载,需要手动修改Cargo.toml添加依赖。
[dependencies]
rand = "0.5.5"
相关知识点:
- 语义版本号:添加依赖包时需要同时指定版本号,版本号格式:MAJOR.MINOR.PATCH,实际引用包的版本和更新包的版本会参照这个版本号规则进行一些自动处理,会加载MAJOR.MINOR.x的最新版本。
- 依赖包锁定:使用cargo编译后会自动生成一个Cargo.lock文件,其中包含了当前引用的扩展包及其实际版本号;如果不修改Cargo.toml文件,下次编译时会自动加载这个文件中定义的包及版本,否则会再次从包管理库中加载,并使用当前兼容的最新版本,以及更新Cargo.lock文件。
- 依赖包更新:有两个方式:修改Cargo.toml文件,这种方式可以指定任何版本;使用cargo update命令,这种方式只能更新到兼容的最新版本。
- 左闭右开:生成随机数的gen_range方法有两个参数,生成的数字范围包括左边的数字,小于右边的数字。
- 依赖包文档:使用cargo doc –open会生成并打开整个项目的文档,通过这个文档可以获取到依赖包的所有开放API,还可以查看到对应的源码。
比较猜测和秘密数字
这一部分控制数字的比较过程,让游戏能够顺利的玩下去。还是先看代码。
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
这一部分增加了输入字符的数据类型转换,数字的比较逻辑。如果输入的不是数字则会提示重新输入;如果输入的数字不等于秘密数字,也会提示重新输入,直到输入相等的数字,则跳出循环,程序结束运行。
相关知识点:
- 类型转换:parse可以将字符串转换为数字类型,u32代表数字类型为无符号32位整数;parse返回一个枚举类型Result,这里使用一个条件表达式进行处理,Ok则返回这个数字,Err则触发循环语句continue。
- 比较大小:所有可以比较的东西都有一个cmp方法,其结果是一个枚举类型Ordering;这里使用一个条件表达式进行处理,输入的数字大或者小只输出对应的提示,继续进行下一轮循环,如果输入的数字正好等于秘密数字,则输出提示,同时break循环。
- 循环语句:使用循环语句是为了让用户可以多次猜数字,直到猜出正确的数字。这里使用loop{}语句,其中可以使用continue和break控制循环的逻辑。
最后你可以使用cargo run来运行这个程序,玩几把。
发表评论
相关文章
国内AI资源汇总,AI聊天、AI绘画、AI写作、AI视频、AI设计、AI编程、AI音乐等,国内顺畅访问,无需科学上网。
扫码或点击进入:萤火AI大全
文章分类
最新评论