laitimes

Rust learns notes (fifty-four) pattern (matching) grammar

author:Everything is not ordinary coding

Matches literals

Pattern matching can directly match literal values, for example:

fn main() {
    let x = 1;

    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}
           

Matches a named variable

A named variable is an irrefutable pattern that can match any value, for example:

fn main() {
    let x = Some(5);
    let y = 10;

    match x {
        Some(50) => println!("Got 50"),
        Some(y) => println!("Matched, y = {:?}", y),//Some(y)匹配的是x,即Some(5),所以此处y是5
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end: x = {:?}, y = {:?}", x, y);
}
           

Run output:

Matched, y = 5
at the end: x = Some(5), y = 10
           

Because the y in the pattern match is out of scope after the pattern match, the y printed later is the outer y.

Multiple matches

In match expressions, using |(or) syntax, you can match multiple patterns, such as:

fn main() {
    let x = 1;

    match x {
        1 | 2 => println!("one or two"),
        3 => println!("three"),
        _ => println!("anything"),
    }

    let x = Some(5);

    match x {
        Some(1 | 2 | 5) => println!("here"),
        _ => println!("la la la"),
    }
}
           

use.. = to match a range of values

example:

fn main() {
    let x = 5;

    match x {
        1..=5 => println!("one through five"),
        _ => println!("something else"),
    }

    let x = 'c';

    match x {
        'a'..='j' => println!("early ASCII letter"),
        'k'..='z' => println!("late ASCII letter"),
        _ => println!("something else"),
    }
}
           

Deconstruct to decompose values

You can use patterns to deconstruct structs, enumerations, tuples, and thus refer to different parts of these type values. example:

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 0, y: 7 };

    let Point { x: a, y: b } = p;
    assert_eq!(0, a);
    assert_eq!(7, b);

    let Point { x, y } = p;
    assert_eq!(0, x);
    assert_eq!(7, y);

    match p {
        Point { x, y: 0 } => println!("On the x axis at {}", x),//匹配x随意,y是0的情况
        Point { x: 0, y } => println!("On the y axis at {}", y),//匹配y随意,x是0的情况
        Point { x, y } => println!("On neither axis: ({}, {})", x, y),//匹配x随意,y也随意的情况
    }
}
           

Deconstruct enumerations

enum Message {
    Quit,
    Move { x: i32, y: i32 },//结构体枚举变体
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn main() {
    let msg = Message::ChangeColor(0, 160, 255);

    match msg {
        Message::Quit => {
            println!("The Quit variant has no data to destructure.")
        }
        Message::Move { x, y } => {
            println!(
                "Move in the x direction {} and in the y direction {}",
                x,
                y
            );
        }
        Message::Write(text) => println!("Text message: {}", text),
        Message::ChangeColor(r, g, b) => {
            println!(
                "Change the color to red {}, green {}, and blue {}",
                r,
                g,
                b
            )
        }
    }
}
           

Deconstruct nested structs and enumerations

enum Color {
    Rgb(i32, i32, i32),
    Hsv(i32, i32, i32),
}

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(Color),
}

fn main() {
    let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));

    match msg {
        Message::ChangeColor(Color::Rgb(r, g, b)) => {
            println!("Change the color to red {}, green {}, and blue {}", r, g, b)
        }
        Message::ChangeColor(Color::Hsv(h, s, v)) => {
            println!(
                "Change the color to hue {}, saturation {}, and value {}",
                h, s, v
            )
        }
        _ => (),
    }
}
           

Deconstruct structs and enumerations

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
}
           

Values are ignored in the pattern

There are several ways to omit an entire or partial value in a pattern match:

  • _
  • _ Works with other modes
  • Use a name that begins with _
  • .. Ignores the rest of the value
fn foo(_: i32, y: i32) {//忽略整个值
    println!("This code only uses the y parameter: {}", y);
}

fn main() {
    foo(3, 4);
}
           
In most cases, when you no longer need a particular function argument, it is best to modify the signature to no longer contain useless arguments. Ignoring function arguments can become particularly useful in some cases, such as when implementing traits, when you need a specific type signature but the function implementation doesn't need a certain argument. The compiler does not warn of the existence of unused function parameters, as if using named parameters.
fn main() {
    //_忽略部分
    let mut setting_value = Some(5);
    let new_setting_value = Some(10);

    match (setting_value, new_setting_value) {
        (Some(_), Some(_)) => {
            //只要求setting_value和new_setting_value都是Some即可,忽略里面的值
            println!("Can't overwrite an existing customized value");
        }
        _ => {
            setting_value = new_setting_value;
        }
    }

    println!("setting is {:?}", setting_value);

    let numbers = (2, 4, 8, 16, 32);

    match numbers {
        (first, _, third, _, fifth) => {
            println!("Some numbers: {}, {}, {}", first, third, fifth)
        }
    }
}
           
fn main() {
    let _x = 5;//_开头会忽略未使用的变量
    let y = 10;//没有_,并且未使用的变量会被编译器警告
}
           
Note that using only _ and using names that begin with an underscore is a subtle difference: for example, _x will still bind the value to the variable, while _ will not bind at all.
fn main() {
    let s = Some(String::from("Hello!"));

    if let Some(_s) = s {
        println!("found a string");
    }

    println!("{:?}", s);//编译器报错,因为_变量仍然会被绑定值,所以 s 的值会移动进 _s,这时s无法使用了。
}
           
fn main() {
    let s = Some(String::from("Hello!"));

    if let Some(_) = s {//只有下划线不会绑定值,所以通过编译
        println!("found a string");
    }

    println!("{:?}", s);
}
           
fn main() {
    struct Point {
        x: i32,
        y: i32,
        z: i32,
    }

    let origin = Point { x: 0, y: 0, z: 0 };

    //使用..忽略x以外的字段
    match origin {
        Point { x, .. } => println!("x is {}", x),
    }
}
           
fn main() {
    let numbers = (2, 4, 8, 16, 32);

    match numbers {//忽略中间的部分(无论中间有多少个),只要第一个和最后一个
        (first, .., last) => {
            println!("Some numbers: {}, {}", first, last);
        }
    }
}
           
fn main() {
    let numbers = (2, 4, 8, 16, 32);

    match numbers {//存在歧义,因为编译器不知道我们要的是中间的哪一个元素,所以无法编译
        (.., second, ..) => {
            println!("Some numbers: {}", second)
        },
    }
}
           

Use Match Guards to provide additional conditions

Match guard is an additional if condition after the match branch, which must also be met if the match is successful. Match guard adapts to more complex scenarios than separate patterns, for example:

fn main() {
    let num = Some(4);

    match num {
        Some(x) if x < 5 => println!("less than five: {}", x),
        Some(x) => println!("{}", x),
        None => (),
    }

    let x = 4;
    let y = false;

    match x {//配合多重匹配
        4 | 5 | 6 if y => println!("yes"),
        _ => println!("no"),
    }
}
           

@Bind

The @ symbol allows us to create a variable that can hold a value while testing whether it matches a pattern. example:

fn main() {
    enum Message {
        Hello { id: i32 },
    }

    let msg = Message::Hello { id: 5 };

    match msg {
        Message::Hello {
            id: id_variable @ 3..=7,//要求id的值在3到7的范围时,将其值保存在id_variable中
        } => {
            println!("Found an id in range: {}", id_variable)
        }
        Message::Hello { id: 10..=12 } => {
            println!("Found an id in another range")
        }
        Message::Hello { id } => {
            println!("Found some other id: {}", id)
        }
    }
}           

Read on