目录
创建一个新项目
处理一次猜测
生成一个秘密数字
使用crate来增加更多功能
Cargo.lock 文件确保构建是可重现的
更新crate到一个新版本
生成一个随机数
比较猜测的数字和神秘数字
使用循环来允许多次猜测
猜测正确后退出
处理无效输入
最终代码
程序会随机生成一个 1 到 100 之间的整数。接着它会提示玩家猜一个数并输入,然后指出猜测是大了还是小了。如果猜对了,它会打印祝贺信息并退出。
projects目录创建一个新项目:
$ cargo new guessing_game
$ cd guessing_game
cargon run 编译运行,打印出:
PS D:\code\Rust\project\guessing_game> cargo run
Compiling guessing_game v0.1.0 (D:\code\Rust\project\guessing_game)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.62s
Running `target\debug\guessing_game.exe`
Hello, world!
use std::io;
fn main(){
println!("猜猜数字是几!");
println!("请输入你的答案");
let mut guess=String::new(); //mut(可变性,添加后让变量可变)
//String::new()函数会返回一个String的新实例
//::语法表明new是String类型的一个关联函数
let num=0; //rust中,变量默认不变
io::stdin()
.read_line(&mut guess) //.read_line方法获取用户输入,并将&mut guess作为参数传递给read_line()
.expect("无法读取");
println!("你猜的是{}",guess);
}
运行结果
PS D:\code\Rust\project\guessing_game> cargo run
Compiling guessing_game v0.1.0 (D:\code\Rust\project\guessing_game)
warning: unused variable: `num`
--> src\main.rs:9:9
|
| ^^^ help: if this is intentional, prefix it with an underscore: `_num`
|
= note: `#[warn(unused_variables)]` on by default
warning: `guessing_game` (bin "guessing_game") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.57s Running `target\debug\guessing_game.exe`
猜猜数字是几!
请输入你的答案
1
你猜的是1
crate:一个Rust代码包。
rand crate :是一个库crate
库crate:可以包含任意被其他程序使用的代码,但是不能独自执行
Cargo 对外部 crate 的运用:使用rand编写代码需要修改Cargon.toml文件,引入rand依赖。打开此文件并将下面这一行添加到 [dependencies]
表块标题之下。
rand = "0.8.3"
在 [dependencies]
表块中,你要告诉 Cargo 本项目依赖了哪些外部 crate 及其版本。
Cargo 默认只会寻找大于或等于 0.8.3
而小于 0.9.0
的版本
$ cargo update
Updating crates.io index
Updating rand v0.8.3 -> v0.8.4
使用 rand
来生成一个猜测的数字
use std::io;
use rand::Rng; //Rng 是一个 trait,它定义了随机数生成器应实现的方法
fn main() {
println!("Guess the number!");
/*
1. 调用 rand::thread_rng 函数来为我们提供将要使用的特定随机数生成器:
它位于当前执行线程的本地环境中,并从操作系统获取 seed。
2. 调用随机数生成器的 gen_range 方法:
由我们刚才使用 use rand::Rng 语句引入的 Rng trait 定义。
gen_range 方法获得一个区间表达式(range expression)作为参数,并在区间内生成一个随机数。
3. rand::thread_rng().gen_range(start..end) //包括起始端,但排除终止端
*/
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);
}
运行结果
PS D:\code\Rust\project\guessing_game> cargo run
Compiling guessing_game v0.1.0 (D:\code\Rust\project\guessing_game)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.71s Running `target\debug\guessing_game.exe`
Guess the number!
The secret number is: 90
Please input your guess.
3
You guessed: 3
PS D:\code\Rust\project\guessing_game> cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
Running `target\debug\guessing_game.exe`
Guess the number!
The secret number is: 30
Please input your guess.
注:运行 cargo doc --open
命令来构建所有本地依赖提供的文档,并在浏览器中打开。例如,假设你对 rand
crate 中的其他功能感兴趣,你可以运行 cargo doc --open
并点击左侧导航栏中的 rand
。
现在有了用户输入和一个随机数,我们可以比较它们。这个步骤如示例 2-4 所示。注意这段代码还不能通过编译,我们稍后会解释。
use rand::Rng;
//标准库引入了一个叫做 std::cmp::Ordering 的类型到作用域中:
//Ordering 也是一个枚举,不过它的成员是 Less、Greater 和 Equal。
use std::cmp::Ordering;
use std::io;
fn main() {
// --snip--
println!("Guess the number!");
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let mut guess = String::new();
o::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {}", guess);
//new
/*
1. cmp 方法用来比较两个值并可以在任何可比较的值上调用:
它获取一个被比较值的引用:这里是把 guess 与 secret_number 做比较。
然后它会返回一个刚才通过 use 引入作用域的 Ordering 枚举的成员。
使用一个 match 表达式,根据 Ordering 成员来决定接下来做什么。
2. match 表达式由分支(arm) 构成:
一个分支包含一个用于匹配的模式(pattern),
给到 match 的值与分支模式相匹配时,应该执行对应分支的代码。
*/
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
编译错误:这里有不匹配的类型。guess是String类型,二secret_number是数字类。
Rust 中有好几种数字类型拥有 1 到 100 之间的值:32 位数字 i32
、32 位无符号数字 u32
、64 位数字 i64。
所以我们必须把从输入中读取到的 String
转换为一个真正的数字类型,才好与秘密数字进行比较。这可以通过在 main
函数体中增加如下两行代码来实现:
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);
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
// --snip--
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
//------------------new-------------------
/*1.创建了一个叫做 guess 的变量:
Rust 允许用一个新值来遮蔽 (shadow) guess 之前的值.
允许我们复用 guess 变量的名字,而不是被迫创建两个不同变量.
2. 将这个新变量绑定到 guess.trim().parse() 表达式上:
表达式中的 guess 是指原始的 guess 变量,
String 实例的 trim 方法会去除字符串开头和结尾的空白字符,
用户必须输入 enter 键才能让 read_line 返回,并输入他们的猜想,这会在字符串中增加一个换行符
3. 字符串的 parse 方法 :将字符串解析成数字。
通过 let guess: u32 指定需要解析的数字类型
4. 使用 Result 类型来处理潜在的错误”:
*/
let guess: u32 = guess.trim().parse().expect("Please type a number!");
//----------------------------------------
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
即便是在猜测之前添加了空格,程序依然能判断出用户猜测了 76。多运行程序几次,输入不同的数字来检验不同的行为:猜一个正确的数字,猜一个过大的数字和猜一个过小的数字。
loop
关键字创建了一个无限循环。我们会增加循环来给用户更多猜数字的机会:
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);
// --snip--
println!("The secret number is: {}", secret_number);
//new:loop循环
loop {
println!("Please input your guess.");
// --snip--
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please type a number!");
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
}
用户总能使用 ctrl-c 终止程序。不过还有另一个方法跳出无限循环,就是“比较猜测的数字和秘密数字”部分提到的 parse
:如果用户输入的答案不是一个数字,程序会崩溃。我们可以利用这一点来退出。
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);
// --snip--
println!("The secret number is: {}", secret_number);
//new:loop循环
loop {
println!("Please input your guess.");
// --snip--
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please type a number!");
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;
}
}
}
}
使用break
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);
println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
let mut guess = String::new();
// --snip--
//将 expect 调用换成 match 语句:实现遇到错误就崩溃转换成处理错误
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);
// --snip--
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
运行结果
Guess the number!
The secret number is: 56
Please input your guess.
j
Please input your guess.
1
You guessed: 1
Too small!
Please input your guess.
56
You guessed: 56
You win!
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;
}
}
}
}