Lv777

Lv777

github
twitter
jike
playstation
xiaoyuzhou

Control Flow

There is not much difference in control flow in Rust compared to other languages.

if#

The condition of if does not include (), and the condition must be of type bool.

if is an expression, achieving the effect of the JavaScript ternary operator directly:

let x = if true { 1 } else { 2 }

Loops#

The loop control loop is an infinite loop that I have never seen before. It can be terminated and skipped using break and continue. In Rust, break can also return a value. The concepts of break, continue, and loop labels are also present in the for loop in JavaScript, but I haven't encountered them much in ES6.

The standard library Range combined with for feels interesting. When writing loops in JavaScript, I often wonder why there isn't a concise solution to control the number of iterations. Now this satisfies that.

match#

match is similar to switch in JavaScript, with strict checks to ensure that all possibilities are exhausted. It can be used with [[data types#enums]] to match and extract values contained in enum members.

let value = match some_value {
    Some(i) => i,
    None => 0
}

You can use the wildcard other (thought other was a keyword) or _ to handle other scenarios. The wildcard should be written as the last condition, otherwise the conditions written after it will be completely ineffective.

match some_num {
    1 => call(),
    3 => check(),
    other => println!("{}", other),
    // You can also use _ to not capture the specific value of the remaining cases
    // _ => (),
}

if let#

For scenarios where only one case needs to be handled, the if let syntax is more concise than match, but it lacks the exhaustive check.

if let Some(value) = some_value {
    println!("{}", value);
}

? Operator#

Similar to the optional chaining in JavaScript, it can be used to propagate errors or None values in Option and Result. It can only be written within the body of a function that is compatible with the return value. For example, to use ? with Result, the function must return Result. One difference is that with Result, it can be used anywhere in the function body, and doing so will cause an early termination and return Result::Err.

Pattern Matching#

A pattern is the syntax used in Rust to match the structure of types. It is somewhat similar to JavaScript's destructuring assignment, but with a slightly different logic. However, it can be used in more scenarios, and most control flows can be achieved using pattern matching.

The let statement can be used for pattern matching, where the pattern on the left side matches the expression on the right side. In the branches of match, the pattern on the left side matches the expression on the right side of the match keyword. In the if let statement, the pattern on the left side matches the expression on the right side.

let (x, y) = (1, 2);

match some_value {
    Some(4) | Some(5) => {},
    Some(x) => {},
    None => {}
}

if let 1..=3 = some_value {
} else if is_true{
} else {
}

// Destructuring a struct
let User { name: username, age } = user;

In this sense, if let is somewhat similar to the syntax if (pattern matching result).

Refutability#

If an expression has the possibility of not matching a pattern, then the pattern is refutable, such as the branch conditions in match. Otherwise, it is irrefutable. It can also be said that in cases where all possibilities are exhausted, the pattern is irrefutable. let and for only accept irrefutable patterns.

Ignoring Values in Patterns#

  1. Use _ to ignore a single value, and it can be repeated within a pattern.
  2. Use .. to ignore the remaining values, but it must ensure that the ignored part is unambiguous.

Matching Guards#

After the branch condition in match, an if keyword can be used to add a guard, which is an additional matching condition.

match some_value {
    Some(1) | Some(2) => {},
    Some(v) if v > 0 => {},
    Some(_) => {},
    _ => {}
}

The if added applies to the entire pattern before it. If multiple patterns are specified using the | operator, the if before it has higher priority. I will probably be caught by this in the future.

match x {
    // This will not match no matter what x is
    1 | 2 | 3 if false => {},
    _ => {}
}

If you want to simultaneously capture a variable and match a pattern, you can use @ binding.

match user {
    // The age here is used for matching, and the value of age cannot be accessed in the following block
    User { age: 1..=18, .. } => {},
    // This way, it can be used
    User { age: user_age @ 20..=35, .. } => {}
}
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.