控制流

控制流的意思是告诉你的代码在不同的情况下该怎么做。最简单的控制流是if

fn main() {
    let my_number = 5;
    if my_number == 7 {
        println!("It's seven");
    }
}

另外注意,你用的是==而不是===是用来比较的,=是用来赋值的(给一个值)。另外注意,我们写的是if my_number == 7而不是if (my_number == 7)。在Rust中,你不需要用if的括号。

else ifelse给你更多的控制:

fn main() {
    let my_number = 5;
    if my_number == 7 {
        println!("It's seven");
    } else if my_number == 6 {
        println!("It's six")
    } else {
        println!("It's a different number")
    }
}

这打印出It's a different number,因为它不等于7或6。

您可以使用 &&(和)和 ||(或)添加更多条件。

fn main() {
    let my_number = 5;
    if my_number % 2 == 1 && my_number > 0 { // % 2 means the number that remains after diving by two
        println!("It's a positive odd number");
    } else if my_number == 6 {
        println!("It's six")
    } else {
        println!("It's a different number")
    }
}

这打印出的是It's a positive odd number,因为当你把它除以2时,你有一个1的余数,它大于0。

你可以看到,过多的ifelseelse if会很难读。在这种情况下,你可以使用match来代替,它看起来更干净。但是您必须为每一个可能的结果进行匹配。例如,这将无法工作:

fn main() {
    let my_number: u8 = 5;
    match my_number {
        0 => println!("it's zero"),
        1 => println!("it's one"),
        2 => println!("it's two"),
        // ⚠️
    }
}

编译器说:

error[E0004]: non-exhaustive patterns: `3u8..=std::u8::MAX` not covered
 --> src\main.rs:3:11
  |
3 |     match my_number {
  |           ^^^^^^^^^ pattern `3u8..=std::u8::MAX` not covered

这就意味着 "你告诉我0到2,但u8可以到255。那3呢?那4呢?5呢?" 以此类推。所以你可以加上_,意思是 "其他任何东西"。

fn main() {
    let my_number: u8 = 5;
    match my_number {
        0 => println!("it's zero"),
        1 => println!("it's one"),
        2 => println!("it's two"),
        _ => println!("It's some other number"),
    }
}

那打印It's some other number

记住匹配的规则:

  • 你写下match,然后创建一个{}的代码块。
  • 在左边写上模式,用=>胖箭头说明匹配时该怎么做。
  • 每一行称为一个 "arm"。
  • 在arm之间放一个逗号(不是分号)。

你可以用匹配来声明一个值。

fn main() {
    let my_number = 5;
    let second_number = match my_number {
        0 => 0,
        5 => 10,
        _ => 2,
    };
}

second_number将是10。你看到最后的分号了吗?那是因为,在match结束后,我们实际上告诉了编译器这个信息:let second_number = 10;

你也可以在更复杂的事情上进行匹配。你用一个元组来做。

fn main() {
    let sky = "cloudy";
    let temperature = "warm";

    match (sky, temperature) {
        ("cloudy", "cold") => println!("It's dark and unpleasant today"),
        ("clear", "warm") => println!("It's a nice day"),
        ("cloudy", "warm") => println!("It's dark but not bad"),
        _ => println!("Not sure what the weather is."),
    }
}

这打印了It's dark but not bad,因为它与skytemperature的 "多云"和 "温暖"相匹配。

你甚至可以把if放在match里面。这就是所谓的 "match guard"。

fn main() {
    let children = 5;
    let married = true;

    match (children, married) {
        (children, married) if married == false => println!("Not married with {} children", children),
        (children, married) if children == 0 && married == true => println!("Married but no children"),
        _ => println!("Married? {}. Number of children: {}.", married, children),
    }
}

这将打印Married? true. Number of children: 5.

在一次匹配中,你可以随意使用 _ 。在这个关于颜色的匹配中,我们有三个颜色,但一次只能选中一个。

fn match_colours(rbg: (i32, i32, i32)) {
    match rbg {
        (r, _, _) if r < 10 => println!("Not much red"),
        (_, b, _) if b < 10 => println!("Not much blue"),
        (_, _, g) if g < 10 => println!("Not much green"),
        _ => println!("Each colour has at least 10"),
    }
}

fn main() {
    let first = (200, 0, 0);
    let second = (50, 50, 50);
    let third = (200, 50, 0);

    match_colours(first);
    match_colours(second);
    match_colours(third);

}

这个将打印:

Not much blue
Each colour has at least 10
Not much green

这也说明了match语句的作用,因为在第一个例子中,它只打印了Not much blue。但是first也没有多少绿色。match语句总是在找到一个匹配项时停止,而不检查其他的。这就是一个很好的例子,代码编译得很好,但不是你想要的代码。

你可以创建一个非常大的 match 语句来解决这个问题,但是使用 for 循环可能更好。我们将很快讨论循环。

匹配必须返回相同的类型。所以你不能这样做:

fn main() {
    let my_number = 10;
    let some_variable = match my_number {
        10 => 8,
        _ => "Not ten", // ⚠️
    };
}

编译器告诉你:

error[E0308]: `match` arms have incompatible types
  --> src\main.rs:17:14
   |
15 |       let some_variable = match my_number {
   |  _________________________-
16 | |         10 => 8,
   | |               - this is found to be of type `{integer}`
17 | |         _ => "Not ten",
   | |              ^^^^^^^^^ expected integer, found `&str`
18 | |     };
   | |_____- `match` arms have incompatible types

这样也不行,原因同上。

fn main() {
    let some_variable = if my_number == 10 { 8 } else { "something else "}; // ⚠️
}

但是这样就可以了,因为不是match,所以你每次都有不同的let语句。

fn main() {
    let my_number = 10;

    if my_number == 10 {
        let some_variable = 8;
    } else {
        let some_variable = "Something else";
    }
}

你也可以使用 @match 表达式的值起一个名字,然后你就可以使用它。在这个例子中,我们在一个函数中匹配一个 i32 输入。如果是4或13,我们要在println!语句中使用这个数字。否则,我们不需要使用它。

fn match_number(input: i32) {
    match input {
    number @ 4 => println!("{} is an unlucky number in China (sounds close to 死)!", number),
    number @ 13 => println!("{} is unlucky in North America, lucky in Italy! In bocca al lupo!", number),
    _ => println!("Looks like a normal number"),
    }
}

fn main() {
    match_number(50);
    match_number(13);
    match_number(4);
}

这个打印:

Looks like a normal number
13 is unlucky in North America, lucky in Italy! In bocca al lupo!
4 is an unlucky number in China (sounds close to 死)!