Rust学习笔记——基于官网和Rust语言圣经(二、猜数游戏)
前面的hello world项目还是太old school了,这样用一个猜数字的游戏来快速了解下rust语言,以及为啥cargo那么好用的原因。不要拘束新的语法点,后面都会详细介绍!
2.1猜数游戏:一次猜测
-本节您将学会:
·let、match等方法
·相关的函数
·外部的crate
·...
猜数游戏-目标
-生成一个1到100间的随机数
-提示玩家输入一个猜测
-猜完之后,程序会提示猜测是太小了还是太大了
-如果猜测正确,那么打印出一个庆祝信息,程序退出
代码1
use std::io; // prelude
fn main() {
println!("猜数!");
println!("猜测一个数");
let mut guess = String::new(); //设置guess为可变的 rust默认情况下变量不可变
io::stdin().read_line(&mut guess).expect("无法读取行"); // 引入一个stdin库,通过read_line获得用户输入,并放入guess中,guess也需要可变的(随着用户的输入而改变),&取地址符号:表示引用,在代码不同地方访问同一个数据。expect:若是错误就会终止运行
println!("你猜测的数是:{}",guess); //{},按照后面顺序,显示
}
代码说明:
默认变量不可变如:
let foo = 1;
let bar = foo; // immutable
foo = 2;
read_line()返回一个io::Result
io::Result Ok,Err
ok表示操作成功
Err表示操作失败,还包括失败的原因
运行结果:
2.2猜数游戏:生成神秘数字
库的网站:https://crates.io/
比如我们要用生成随机数的库及其介绍
如何添加包
在cargo.toml的dependencies下添加需要的包
由于我们装了vs插件所以自己都安装了,不然是需要自己cargo build更新的
这里更新下,改成rand = "0.7.3"
更新完后,可以打开cargo.lock中可以看到更新好的包。类似于npm思想
这样的好处:如果有新的包会对项目产生冲突,但是这个lock记录了开发者用的包,这样所有人拿到你的项目都可以直接运行。cargo lock不要自己手动修改!
代码
use std::io; // prelude
use rand::Rng; // trait
fn main() {
println!("猜数游戏!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("神秘数字是:{}",secret_number);
println!("猜测一个数");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("无法读取行");
println!("你猜测的数是:{}",guess);
}
运行结果
2.3猜数游戏:比较猜测数字与神秘数字
引入std::cmp::Ordering: 他有三个枚举类型,分别是大小等于。
use std::io; // prelude
use rand::Rng; // trait
use std::cmp::Ordering;
fn main() {
println!("猜数游戏!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("神秘数字是:{}",secret_number);
println!("猜测一个数");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("无法读取行");
println!("你猜测的数是:{}",guess);
match guess.cmp(&secret_number){
std::cmp::Ordering::Less => println!("Too small!"),
std::cmp::Ordering::Equal => println!("You win!"),
std::cmp::Ordering::Greater => println!("Too big!"),
}
}
若直接运行会报错,因为比较两个值的类型不一样。
代码
use std::io; // prelude
use rand::Rng; // trait
fn main() {
println!("猜数游戏!");
let secret_number = rand::thread_rng().gen_range(1, 101); //i32 u32 i64
println!("神秘数字是:{}",secret_number);
println!("猜测一个数");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("无法读取行");
println!("你猜测的数是:{}",guess);
// shadow
let guess:u32 = guess.trim().parse().expect("Please type a number!"); //trim把前后空格去掉(包括回车\n) parse把字符串解析成某种数字类型
match guess.cmp(&secret_number){
std::cmp::Ordering::Less => println!("Too small!"),
std::cmp::Ordering::Equal => println!("You win!"),
std::cmp::Ordering::Greater => println!("Too big!"),
}
}
rust为静态的强类型语言
需要把guess从string变成u32,这里修改后,本来是i32的secret_number也会变成u32,此外我们可以看到,rust中可以使用重复变量,来减少损耗,且智能上下文推理的能力。
运行结果
猜数游戏:允许多次猜测
如要无限猜测需要加入无限循环
代码
use std::io; // prelude
use rand::Rng; // trait
fn main() {
println!("猜数游戏!");
let secret_number = rand::thread_rng().gen_range(1, 101); //i32 u32 i64
println!("神秘数字是:{}",secret_number);
loop {
println!("猜测一个数");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("无法读取行");
println!("你猜测的数是:{}",guess);
// shadow
let guess:u32 = guess.trim().parse().expect("Please type a number!");
match guess.cmp(&secret_number){
std::cmp::Ordering::Less => println!("Too small!"),
std::cmp::Ordering::Equal => println!("You win!"),
std::cmp::Ordering::Greater => println!("Too big!"),
}
}
}
将猜测部分代码放入loop循环中,即可完成。
运行结果
我们可以看到可以实现,但是还有一点点不健壮性。比如我们输入的不是数字呢?还有猜测都成功了,应该退出程序啊!
修改
先处理不能退出循环的问题:
use std::io; // prelude
use rand::Rng; // trait
use std::cmp::Ordering;
fn main() {
println!("猜数游戏!");
let secret_number = rand::thread_rng().gen_range(1, 101); //i32 u32 i64
println!("神秘数字是:{}",secret_number);
loop {
println!("猜测一个数");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("无法读取行");
println!("你猜测的数是:{}",guess);
// shadow
let guess:u32 = guess.trim().parse().expect("Please type a number!");
match guess.cmp(&secret_number){
Ordering::Less => println!("Too small!"),
Ordering::Equal => {
println!("You win!");
break; //rust退出循环也是break
},
Ordering::Greater => println!("Too big!"),
}
}
}
在判断等于的时候加入break跳出循环!
修复非数字输入:
我们可以利用expect返回ok和err来进行一个match选择。
use std::io; // prelude
use rand::Rng; // trait
use std::cmp::Ordering;
fn main() {
println!("猜数游戏!");
let secret_number = rand::thread_rng().gen_range(1, 101); //i32 u32 i64
// println!("神秘数字是:{}",secret_number);
loop {
println!("猜测一个数");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("无法读取行");
println!("你猜测的数是:{}",guess);
// shadow
let guess:u32 = match guess.trim().parse(){
Ok(num) => num, // ok就正常赋值
Err(_) => continue, // 错误就重新输入,_表示不关心错误信息
};
match guess.cmp(&secret_number){
Ordering::Less => println!("Too small!"),
Ordering::Equal => {
println!("You win!");
break; //rust退出循环也是break
},
Ordering::Greater => println!("Too big!"),
}
}
}
未完待续