【Rust学习记录】2. 猜数游戏——尝试代码编写
输入与输出的尝试
创建项目
1 | cargo new guess_game |
就是之前介绍的,用 cargo 创建项目的步骤,run 成功了就表明没问题啦
1 | use std::io; |
use
:就是 Rust 里的导入语句,这里的意思是导入std
库里的io
模块。let
:就是 Rust 里的定义语句,let a = b;
就是定义一个新的变量a
,值为b
。但值得一提的是,和其他所有程序都不一样,Rust 里直接定义的变量都是const
常量,不可变!需要用mut
关键词声明这个变量是可变的变量。string::new()
:没什么好说的,new
了一个String
类型,是空白的字符串。io::stdin().read_line(&mut guess)
:也就是调用io
模块里的stdin
实例的read_line
函数,如果没有写use
,也可以用std::io::stdin
表示,&
和 C++ 里一样,是引用的概念,也就是说,定义了一个新的引用,和上面的guess
指向同一个地址,用来接输入。.expect
就是异常处理语句,在执行完read_line
后,会返回一个Result
类型的值,通常是一个枚举类型,Ok
和Err
两个值,Ok
就是执行成功,并且附带代码产生的结果值,这里就是输入的字节数;Err
就是执行错误,附带错误原因。用expect
就可以很方便地处理异常,而不用再写各 if-else。- 值得一提的是,不写
expect
的话,虽然能编译通过,但 Rust 会提示你有个地方没处理异常,就像这样:
(听说有人不喜欢写异常处理是吧)
最后一句,就是标准的格式化花括号占位输出,没什么好说的。
引入第三方包的尝试
声明依赖
一般语言的标准库都有生成随机数的函数,但rust没有。所以我们需要引入rust官方提供的一个随机数包——rand
打开Cargo.toml文件,在dependencies后面添加rand包。
1 | [package] |
0.3.14版本就是版本号。
然后再build一次项目,cargo就会自动帮你搜索包以及对应的并下载了,包的信息一般是从 crates.io 获取
cargo.lock和cargo update
cargo引入了一个独特的机制来保证依赖的版本问题,让所有人在构建这个项目的时候都得到相同的结果。你第一次构建项目的时候,cargo就会遍历我们声明的依赖以及版本号,把它写到 lock 文件里,后面再构建的时候,就会都使用这个版本的依赖了,除非手动升级到其他版本。
如果实在想升级,使用 cargo update
命令就会无视 lock 强行升级依赖
使用match进行分支控制的尝试
rust提供了match语法来进行更简洁的分支控制。
1 | use std::io; |
这段代码里:
use
了一个Ordering
的模块,这个模块提供了顺序对应的枚举类型,也就是Less
,Greater
,Equal
trim().parse()
语句用来作类型转换,因为gen_range
生成的secret_number
是i32
类型,无法直接与输入的字符串进行比较,所以作了一个类型转换;其中trim()
就是去掉首尾多余的字符,空格换行什么的;parse()
是用于将字符串解析为对应数值类型的方法,同样也会抛出Result
可以用于异常处理match guess.cmp
:就是通过match
语法进行分支控制,把guess.cmp()
的结果丢到下面去匹配,匹配到什么就执行什么的语句。其中cmp
返回的就是Ordering
这个枚举类型。实际中,这个枚举类型也可以自己定义,方便自己的分支控制。传统的if-else
也能实现这个逻辑就是。
PS:大概了解了一下 if-else
和 match
的比较,两者应该主要是在可读性上的区别比较明显。
在可读性上,if-else
只接受 bool 值的二类判断。当有复杂条件的时候,就需要多层嵌套 if-else
比较难看。相对的,match
可以自定义枚举类型,在多类判断的时候,写法也更简洁,可读性更佳。当然,二类判断当属 if-else
。
在性能上,当匹配的模式非常多的情况下,match
可以在编译时就完成判断,而 if-else
是在运行的时候完成判断,在极端的情况下,match
的性能会更佳(但我觉得在这种语句上纠性能的意义并不大)。
另外了解了一下,if-else
的语法和 C++ 基本一样,就不另外写了,书上目前也没有介绍 if-else
。
循环的尝试
1 | use std::io; |
想使用一个 while True
循环也很简单,在 Rust 里就是一个 loop
语法,外带 break
,没什么多说的,这里注意定义 guess
变量要在 loop
里,不然 read_line
会不断的在 guess
后面添加字符,就会导致无法转换成数字,报错退出。
那么在循环里有一个问题就很明显了,那就是 expect
语句不是我所理解常规的 try-catch
异常处理语句,它并没有捕获+后处理的步骤,所以它是会导致程序报错退出的。
那怎么来进行异常处理呢?之前也说过,Result
返回的是一个枚举类型 Ok
和 Err
。那不就是,用 match
来处理就完了嘛?~
1 | use std::io; |
修改后的代码是这样的,我们用 match
来处理 parse()
的返回值,之前也说过,Ok
会附带执行成功的值,所以 Ok(num)
表示,用 num
来匹配 Ok
里面带的成功的返回值,=>
表示返回 num
值;Err(_)
就是表示,用 _
来匹配错误信息,因为不需要用,所以用 _
就完了,然后执行错误处理,输出+继续输入;值得一提的是这里好像说明了 Rust 的函数返回机制,好像不需要写 return
,直接一个变量名就是返回了。
OK,到目前为止,初步的编程尝试已经结束了,看了下后面的章节介绍,应该会是更结构化的东西。
- 标题: 【Rust学习记录】2. 猜数游戏——尝试代码编写
- 作者: TwoSix
- 创建于 : 2023-03-25 14:45:41
- 更新于 : 2024-07-04 23:52:28
- 链接: https://twosix.page/2023/03/25/【Rust学习记录】2-猜数游戏——尝试代码编写/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。