Rust权威指南阅读笔记(二)猜数游戏
在Rust下,所有变量都默认不可变,如果要声明一个可变的变量,需要在声明时加 mutlet foo = 1;
foo = 2;// Error!!
let mut bar = 2;
bar = 3; // No error!添加库
所有的库都在crates.io这个网站下
Cargo换源
1、进入 $HOME/.cargo 文件夹中。我的目录是 C:\Users\admin\.cargo
2、删除一个名为 .package-cache 的文件
3、创建一个名为 config 的文件,注意不要后缀
4、编辑 config 文件,将下面内容添加进去后,保存退出即可
replace-with = 'sjtu' # 指定使用下面哪个源,修改为source.后面的内容即可
# 中国科学技术大学
registry = "https://mirrors.ustc.edu.cn/crates.io-index"
# 上海交通大学
registry = "https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index/"
# 清华大学
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
# rustcc社区
registry = "https://code.aliyun.com/rustcc/crates.io-index.git"5、cargo build
代码中添加:
在rust代码中添加依赖:在Cargo.toml中添加:
rand = "0.3.14"^ 表示兼容0.3.14的版本
读取输入与错误处理
读一个数
use std::io;
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to read line");.read_line(&mut guess) 这一行调用了 read_line 方法,来从标准输入句柄中获取用户输入。我们还将 &mut guess 作为参数传递给 read_line(),以告诉它在哪个字符串存储用户输入。read_line 的全部工作是,将用户在标准输入中输入的任何内容都追加到一个字符串中(而不会覆盖其内容),所以它需要字符串作为参数。这个字符串应是可变的,以便该方法可以更改其内容。
& 表示这个参数是一个引用(reference),这为你提供了一种方法,让代码的多个部分可以访问同一处数据,而无需在内存中多次拷贝。引用是一个复杂的特性,Rust 的一个主要优势就是安全而简单的使用引用。完成当前程序并不需要了解太多细节。现在,我们只需知道就像变量一样,引用默认是不可变的。因此,需要写成 &mut guess 来使其可变,而不是 &guess。
错误处理
read_line 将用户输入存储到我们传递给它的字符串中,但它也返回一个值——在这个例子中是 io::Result。Rust 标准库中有很多名为 Result 的类型:一个通用的 Result 以及在子模块中的特化版本,比如 io::Result。Result 类型是 枚举(enumerations),通常也写作 enum。枚举类型持有固定集合的值,这些值被称为枚举的成员(variant)。枚举往往与条件表达式 match 一起使用,match 是一种条件语句,在其被执行时,可以方便地匹配不同枚举值来执行不同的代码。
Result 的成员是 Ok 和 Err,Ok 成员表示操作成功,且 Ok 内部包含成功生成的值。Err 成员则意味着操作失败,并且包含失败的前因后果。
Result 类型的值,就像任何类型的值一样,都有为其定义的方法。io::Result 的实例拥有 expect 方法。如果 io::Result 实例的值是 Err,expect 会导致程序崩溃,并显示传递给 expect 的参数。如果 read_line 方法返回 Err,则可能是底层操作系统引起的错误结果。如果 io::Result 实例的值是 Ok,expect 会获取 Ok 中的值并原样返回,以便你可以使用它。在本例中,这个值是用户输入的字节数。
如果不调用 expect,程序也能编译,但会出现警告提示:
$ cargo build
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
warning: unused `Result` that must be used
--> src/main.rs:10:5
|
10 | io::stdin().read_line(&mut guess);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#` on by default
= note: this `Result` may be an `Err` variant, which should be handled
warning: `guessing_game` (bin "guessing_game") generated 1 warning
Finished dev target(s) in 0.59sRust 警告我们没有使用 read_line 的返回值 Result,这表明程序没有处理一个可能发生的错误。
随机数生成
use rand::Rng;
// 注意:gen_range()函数不同版本有不同的参数格式
let secret_number = rand::thread_rng().gen_range(1..101);比较
use std::cmp::Ordering;
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too Small!"),
Ordering::Greater => println!("Too Big!"),
Ordering::Equal => println!("You Win!!");
}Ordering 也是一个枚举,不过它的成员是 Less、Greater 和 Equal。这是比较两个值时可能出现的三种结果。
cmp 方法用来比较两个值并可以在任何可比较的值上调用。它获取一个被比较值的引用:这里是把 guess 与 secret_number 做比较。 然后它会返回一个刚才通过 use 引入作用域的 Ordering 枚举的成员。使用一个 match 表达式,根据对 guess 和 secret_number 调用 cmp 返回的 Ordering 成员来决定接下来做什么。
一个 match 表达式由分支(arm) 构成。一个分支包含一个用于匹配的模式(pattern),给到 match 的值与分支模式相匹配时,应该执行对应分支的代码。Rust 获取提供给 match 的值并逐个检查每个分支的模式。模式和 match 结构是 Rust 中强大的功能,它体现了代码可能遇到的多种情形,并帮助你确保没有遗漏处理
然而这段代码不能编译:
错误的核心表明这里有不匹配的类型(mismatched type)。Rust 有一个静态强类型系统,同时也有类型推断。当我们写出 let guess = String::new() 时,Rust 推断出 guess 应该是 String 类型,并不需要我们写出类型。另一方面,secret_number 是数字类型。Rust 中有好几种数字类型拥有 1 到 100 之间的值:32 位数字 i32、32 位无符号数字 u32、64 位数字 i64,等等。Rust 默认使用 i32,这是 secret_number 的类型,除非额外指定类型信息,或任何能让 Rust 推断出不同数值类型的信息。这里错误的原因在于 Rust 不会比较字符串类型和数字类型。
所以我们必须把从输入中读取到的 String 转换为一个真正的数字类型,才好与秘密数字进行比较。
类型转换
let guess: u32 = guess.trim().parse().expect("Please type a number!");不是已经有了一个叫做 guess 的变量了吗?确实如此,不过 Rust 允许用一个新值来遮蔽 (shadow) guess 之前的值。这允许我们复用 guess 变量的名字,而不是被迫创建两个不同变量,诸如 guess_str 和 guess 之类。我们会在第 3 章介绍变量遮蔽的更多细节,目前暂时只需要知道这个功能通常用作转换值类型。
我们将这个新变量绑定到 guess.trim().parse() 表达式上。表达式中的 guess 是指原始的 guess 变量,其中包含作为字符串的输入。String 实例的 trim 方法会去除字符串开头和结尾的空白字符,我们必须执行此方法才能将字符串与 u32 比较,因为 u32 只能包含数值型数据。用户必须输入 enter 键才能让 read_line 返回,并输入他们的猜想,这会在字符串中增加一个换行符。例如,用户输入 5 并按下 enter,guess 看起来像这样:5\n,\n 代表 “换行”(在 Windows 中,按 enter 键会得到一个回车和一个换行符 \r\n)。trim 方法会消除 \n 或 \r\n,只留下 5。
字符串的 parse 方法 将字符串解析成数字。因为这个方法可以解析多种数字类型,因此需要告诉 Rust 具体的数字类型,这里通过 let guess: u32 指定。guess 后面的冒号(:)告诉 Rust 我们指定了变量的类型。Rust 有一些内建的数字类型;u32 是一个无符号的 32 位整型。对于不大的正整数来说,它是不错的类型,第 3 章还会讲到其他数字类型。另外,程序中的 u32 标注以及与 secret_number 的比较,意味着 Rust 会推断出 secret_number 也是 u32 类型。现在可以使用相同类型比较两个值了!
由于 parse 方法只能用于可以逻辑转换为数字的字符,所以调用它很容易产生错误。例如,字符串中包含 A
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]