Rust权威指南阅读笔记(二)猜数游戏

海哥  金牌会员 | 2024-3-22 17:16:03 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 899|帖子 899|积分 2697

在Rust下,所有变量都默认不可变,如果要声明一个可变的变量,需要在声明时加 mut
  1. let foo = 1;
  2. foo = 2;  // Error!!
  3. let mut bar = 2;
  4. bar = 3;   // No error!
复制代码
添加库

所有的库都在crates.io这个网站下
Cargo换源

1、进入 $HOME/.cargo 文件夹中。我的目录是 C:\Users\admin\.cargo
2、删除一个名为 .package-cache 的文件
3、创建一个名为 config 的文件,注意不要后缀
4、编辑 config 文件,将下面内容添加进去后,保存退出即可
  1. [source.crates-io]
  2. replace-with = 'sjtu' # 指定使用下面哪个源,修改为source.后面的内容即可
  3. # 中国科学技术大学
  4. [source.ustc]
  5. registry = "https://mirrors.ustc.edu.cn/crates.io-index"
  6. # 上海交通大学
  7. [source.sjtu]
  8. registry = "https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index/"
  9. # 清华大学
  10. [source.tuna]
  11. registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
  12. # rustcc社区
  13. [source.rustcc]
  14. registry = "https://code.aliyun.com/rustcc/crates.io-index.git"
复制代码
5、cargo build
代码中添加:

在rust代码中添加依赖:在Cargo.toml中添加:
  1. [dependencies]
  2. rand = "0.3.14"
复制代码
^ 表示兼容0.3.14的版本
读取输入与错误处理

读一个数
  1. use std::io;
  2. let mut guess = String::new();
  3. 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,程序也能编译,但会出现警告提示:
  1. $ cargo build
  2.    Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
  3. warning: unused `Result` that must be used
  4.   --> src/main.rs:10:5
  5.    |
  6. 10 |     io::stdin().read_line(&mut guess);
  7.    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  8.    |
  9.    = note: `#[warn(unused_must_use)]` on by default
  10.    = note: this `Result` may be an `Err` variant, which should be handled
  11. warning: `guessing_game` (bin "guessing_game") generated 1 warning
  12.     Finished dev [unoptimized + debuginfo] target(s) in 0.59s
复制代码
Rust 警告我们没有使用 read_line 的返回值 Result,这表明程序没有处理一个可能发生的错误。
随机数生成
  1. use rand::Rng;
  2. // 注意:gen_range()函数不同版本有不同的参数格式
  3. let secret_number = rand::thread_rng().gen_range(1..101);
复制代码
比较
  1. use std::cmp::Ordering;
  2. match guess.cmp(&secret_number) {
  3.             Ordering::Less    => println!("Too Small!"),
  4.             Ordering::Greater => println!("Too Big!"),
  5.             Ordering::Equal   => println!("You Win!!");
  6. }
复制代码
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 转换为一个真正的数字类型,才好与秘密数字进行比较。
类型转换
  1. 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
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表