Skip to content

本小节目标

判断用户输入与目标数字是否匹配并反馈结果.

控制语句

请复制到本地:

rust
use rand::random_range;
use std::io;

fn main() {
    println!("请猜测一个数");

    let secret_num = random_range(1..=100);

    let mut guess = String::new();
    io::stdin().read_line(&mut guess).expect("读取有误时的报错");

    println!("你猜的是: {}", guess);
    // vvvv 新增代码 vvvv
    if guess == secret_num.to_string() {
        println!("猜对了");
    } else {
        println!("猜错了");
    }
    // ^^^^ 新增代码 ^^^^
}

在这部分代码中, 我们调用 i32 类型上定义的 .to_string() 方法将 secret_num 转化为 String 类型, 然后通过形式

rust
if /* 任意返回布尔值的表达式 */ {
    /* 布尔值为真时执行该语句块 */
}
else
{
    /* 布尔值为假时执行该语句块 */
}

分情况执行不同代码. 我们代码中的 guess == secret_num.to_string() 作为表达式返回的就是 布尔 (bool) 类型, 该类型专门用于逻辑判断, 仅有 truefalse 两个值. 而 == 运算符专门用于比较两个相同类型变量是否具有相同的值, 也正因此必须首先将 i32 类型的 secret_num 转为 String 类型, 然后才能与 IO 输入的 String 类型变量 guess 相比较.

else {..} 语句块作为布尔表达式为假的分支, 整体允许省略, 即写为

rust
if /* .. */ {
    /* .. */
}

此时如果布尔表达式为假, 语句块将被单纯地跳过.

注意

在 C/C++ 中, 布尔表达式必须用括号包裹, 而执行语句块若只有单句则可以略去大括号, 如

c
if (a == 1)
    a-=2;

Rust 恰好与之相反, 布尔表达式允许 (甚至建议) 非必要时略去布尔表达式的括号, 但禁止省略执行语句块的大括号. 如果执意写

rust
if (a == 1)
{
    a = a - 2;
}

代码检查器甚至会警告称

md
unnecessary parentheses around `if` condition
`#[warn(unused_parens)]` (part of `#[warn(unused)]`) on by default

模式匹配

上面的例子用到与 C/C++ 类似的 if-else 控制语句去控制分支, 但在 Rust 中, 更优雅的做法是使用模式匹配. 请复制代码到本地:

rust
use rand::random_range;
use std::{cmp::Ordering, io};

fn main() {
    println!("请猜测一个数");

    let secret_num = random_range(1..=100);

    let mut guess = String::new();
    io::stdin().read_line(&mut guess).expect("读取有误时的报错");

    println!("你猜的是: {}", guess);


    match guess.cmp(&secret_num.to_string()) {
        Ordering::Less => println!("太小了!"),
        Ordering::Greater => println!("太大了!"),
        Ordering::Equal => println!("猜对了!"),
    }
}

这其中, .cmp() 是定义在泛型参数 T 上的方法, 功能也是比较两个相同类型的变量, 接收两个相同类型的引用参数 (&self, &other:Self), 然后返回一个枚举类型 Ordering. Ordering 定义在 std::cmp::Ordering 上, 有三个可能的变体, 即 Ordering::Less, Ordering::GreaterOrdering::Equal.

match 关键字将对返回枚举类型的表达式模式匹配, 在其后的大括号语句块中以 , 分隔依次匹配每个枚举结果, 成功匹配后执行枚举结果对应行 => 后的语句. 模式匹配的强大之处将在后文详细介绍, 此处的确与 if-else 区别不算大.

花活

上述代码的 match 部分由于 Rust 的表达式特性可以写作如下形式:

rust
println!(
    "{}",
    match guess.cmp(&secret_num.to_string()) {
        Ordering::Less => "太小了",
        Ordering::Greater => "太大了",
        Ordering::Equal => "猜对了",
    }
)

合并 use 语句

注意到代码中引入外部包的写法是

rust
use std::{cmp::Ordering, io};

这种写法与

rust
use std::cmp::Ordering;
use std::io;

完全等价.