Rust Lang Book Ch.18 Patterns and Matching

Rust中的Pattern能够包含以下内容:

a) literal

b)Destructured arrays, enums, structs, or tuples

c) 变量

d) 通配符

e) placeholders

以下的都算是pattern:

a) match Arms

b) if let

c) while let

d) for x in y 中的x

e) let PATTERN = EXPRESSION

f) function parameters, 例如&(x, y): &(i32, i32)

 

Refutability

能够match任何传过来的值的是irrefutable pattern。例如let x = 5中的x。

与此对应的,有时可能match不了传过来的值的是refutable pattern,例如let Some(x) = some_option_value;

一般来说,写程序时可以不重视pattern的Refutable和irrefutable之间的差别,但是,在弹出错误信息的时候要能够区别。P.S: Rust只允许match的最多一个arm是irrefutable match。

 

Pattern Syntax

1. 和固定值(literal)做对比

    let x = 1;

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

  

2. Named Variable

let y = 5中的y是一个named variable也是一个irrefutable pattern。

但是named variable也可能只是pattern的一部分。

    let x = Some(5);
    let y = 10;

    match x {
        Some(50) => println!("Got 50"),
        Some(y) => println!("Matched, y = {:?}", y),
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end: x = {:?}, y = {:?}", x, y);
//Output:
//Matched, y = 5
//注意在这里match内是一个新的作用域了,里面的Some(y)里面的y是个named variable,与外层的y=10无关

  

Multiple Patterns

可以用|把多个pattern连起来。

    let x = 1;

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

  

Matching Ranges

使用..=可以一次性匹配一个全闭区间。..=只能和数字或者char搭配使用。

 

    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"),
    }

 

Destructuring

Destructuring Structs

可以带域名,直接按顺序取named variable,也可以在给一部分域名中嵌套其他pattern

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); }

  

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

    match p {
        Point { x, y: 0 } => println!("On the x axis at {}", x),
        Point { x: 0, y } => println!("On the y axis at {}", y),
        Point { x, y } => println!("On neither axis: ({}, {})", x, y),
    }
}

  

Destructuring Enums

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
        ),
    }
}

  

Destructuring Nested Structs and Enums

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
        ),
        _ => (),
    }
}

  

Destructuring Structs and Tuples

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

  

Ignore 

忽略整个待匹配值:_

fn foo(_: i32, y: i32) {
    println!("This code only uses the y parameter: {}", y);
}

忽略部分待匹配值:嵌套的_

    match (setting_value, new_setting_value) {
        (Some(_), Some(_)) => {
            println!("Can't overwrite an existing customized value");
        }
        _ => {
            setting_value = new_setting_value;
        }
    }

  

忽略一个没使用过的变量而不输出警告:在变量名前面加_

fn main() {
    let _x = 5;
    let y = 10;
}

  

忽略没匹配完的值: ..

 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);
//error: `..` can only be used once per tuple pattern
    match numbers {
        (.., second, ..) => {
 --          ^^ can only be used once per tuple pattern
            println!("Some numbers: {}", second)

        },
    }
}

  

Match Guards

 

match guard是match arm之后接着的一个if条件,要求match arm和if 都被满足时才能够匹配。能够支持比pattern更强大的条件。

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

    match x {
        Some(50) => println!("Got 50"),
        Some(n) if n == y => println!("Matched, n = {}", n),
        _ => println!("Default case, x = {:?}", x),
    }

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

  

注意与|连用时,相当于任何一个pattern匹配之后,都要额外匹配这个if语句。

    let x = 4;
    let y = false;

    match x {
        4 | 5 | 6 if y => println!("yes"),
//无论是4,5还是6都需要匹配if y _ => println!("no"), }

  

 

@Bindings

@操作符允许程序员在同一个pattern中把变量保存下来同时测试是否满足条件。基本方法是fieldname: alias @ test_pattern

    enum Message {
        Hello { id: i32 },
    }

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

    match msg {
        Message::Hello {
            id: id_variable @ 3..=7,
        } => println!("Found an id in range: {}", id_variable),
        Message::Hello { id: 10..=12 } => {
//没有使用@,为了10..=12这个测试,就无法保留named variable
            println!("Found an id in another range")
        }
        Message::Hello { id } => println!("Found some other id: {}", id),
    }

  

 

 

Destructuring Structs

posted @ 2020-10-27 23:19  雪溯  阅读(281)  评论(0编辑  收藏  举报