After reading Rust book chapter 18

rust

All the Places Patterns Can Be Used

1-1. match Arms

match VALUE {
    PATTERN => EXPRESSION,
    PATTERN => EXPRESSION,
    PATTERN => EXPRESSION,
}
match x {
    None => None,
    Some(i) => Some(i + 1),
}


1-2. Conditional if let Expressions

fn main() {
    let favorite_color: Option<&str> = None;
    let is_tuesday = false;
    let age: Result<u8, _> = "34".parse();

    if let Some(color) = favorite_color {
        println!("Using your favorite color, {color}, as the background");
    } else if is_tuesday {
        println!("Tuesday is green day!");
    } else if let Ok(age) = age {
        if age > 30 {
            println!("Using purple as the background color");
        } else {
            println!("Using orange as the background color");
        }
    } else {
        println!("Using blue as the background color");
    }
}


1-3. Conditional while let Loops

let mut stack = Vec::new();

stack.push(1);
stack.push(2);
stack.push(3);

while let Some(top) = stack.pop() {
    println!("{}", top);
}


for loops

let v = vec!['a', 'b', 'c'];

for (index, value) in v.iter().enumerate() {
    println!("{} is at index {}", value, index);
}


1-4. let Statements

// (1) 성공
let (x, y, z) = (1, 2, 3);

// (2) 에러
let (x, y) = (1, 2, 3);


1-5. Function Parameters

fn foo(x: i32) {
    // code goes here
}
fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({}, {})", x, y);
}

fn main() {
    let point = (3, 5);
    print_coordinates(&point);
}



Refutability: 패턴 매칭에 실패할까, 아닐까?

fn main() {
    let some_option_value: Option<i32> = None;

    // (1)
    let Some(x) = some_option_value;

    // (2)
    if let Some(x) = some_option_value {
        println!("{}", x);
    }

    // (3)
    if let x = 5 {
        println!("{}", x);
    };
}



Pattern Syntax

3-1. 리터럴과 매칭하기

let x = 1;

// 패턴은 리터럴에 직접 비교할 수 있다.
match **x** {
    1 => println!("하나"),
    2 => println!("둘"),
    3 => println!("셋"),
    _ => println!("나머지"),


3-2. 명명된 변수와 매칭하기


출력 결과 예측하기?

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

    match x {
        Some(50) => println!("50"),

        // 변수 y는 앞서 10을 대입한 변수 y가 아니라 새로운 변수
        // y는 Some 값에 저장된 모든 값과 일치
        // y에 Some 값 안에 저장된 변수 x의 값이 바인딩된다.
        Some(y) => println!("일치, y = {:?}", y),
        _ => println!("일치하지 않음, x = {:?}", x),
    }

    println!("결과: x = {:?}, y = {:?}", x, y);
    // 출력결과: 일치, y = 5
    // 결과: x = Some(5), y = 10
}


3-3. 다중 패턴

let x = 1;

match x {
    1 | 2 => println!("1 또는 2"),
    3 => println!("3"),
    _ => println!("그 외 나머지 값"),
}


3-4. ..= 문법으로 범위 값과 매칭하기

fn main() {
    let x = 5;

    match x {
        1..=5 => println!("one through five"),
        _ => println!("something else"),
    }
}
fn main() {
    let x = 'c';

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


3-5. 값을 분리하여 Destructuring


구조체의 해체

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

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

    // 변수 p에 저장된 구조체의 x와 y필드값에 일치하는 변수 a와 b를 생성한다.
    let Point {x: **a**, y: **b** } = p;
    assert_eq!(0, a);
    assert_eq!(7, b);
}


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

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

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


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

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

    match p {
        // y 필드값이 0 이면서 x 필드값은 어떤 값이든 일치하는 경우, 변수 x를 생성
        Point { x, y: 0 } => println!("x 축 {}에 위치하는 점", x),
        // x 필드값이 0 이면서 y 필드값은 어떤 값이든 일치하는 경우, 변수 y를 생성
        Point { x: 0, y } => println!("y 축 {}에 위치하는 점", y),
        // 위의 두 경우 제외한 모든 경우, 변수 x, y 모두 생성
        Point { x, y } => println!("좌표 ({}, {})에 위치하는 점", x, y),
    }
}


열거자의 해체

// p.123
enum Message {
    Quit, // 연관 데이터를 전혀 갖지 않는다.
    Move { x: i32, y: i32 }, // 익명 구조체를 포함
    Write(String), // 하나의 String값을 포함
    ChangeColor(Color), // 세 개의 i32값을 포함
}

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

    match msg {
        Message::Quit => {
            // 데이터가 없는 열것값은 어떤 값도 해체할 수 없다. Message::Quit 리터럴 값에만 일치하므로 패턴에 변수도 포함하지 않는다.
            println!("Quit: 해체할 값이 없습니다.")
        },
        Message::Move { x, y } => {
            // 구조체와 유사한 형태의 열것값은 구조체를 사용할 때와 유사한 패턴을 사용할 수 있다.
            println!(
                "Move: x = {}, y = {}",
                x,
                y
            );
        },
        Message::Write(text) => println!("Write: {}", text),
        Message::ChangeColor(r, g, b) => {
            println!(
                "ChangeColor: R = {}, G = {}, B = {}",
                r,
                g,
                b
            )
        },
    }
}


중첩된 구조체와 열거자의 해체

// ChangeColor 메시지가 RGB와 HSV 색상을 지원한다면
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!(
                "ChangeColor: R = {}, G = {}, B = {}",
                r,
                g,
                b
            );
        },
        Message::ChangeColor(Color::Hsv(h, s, v)) => {
            println!(
                "ChangeColor: H = {}, S = {}, V = {}",
                h,
                s,
                v
            )
        },
        _ => {}
    },
}


구조체와 튜플의 해체

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


3-6. 패턴의 값 무시하기


_ 패턴으로 값 전체 무시하기

fn foo(_: i32, y: i32) {
    println!("이 함수는 y 매개변수만 사용한다: {}", y);
}

fn main() {
    foo(3, 4);
}


_를 중첩해서 값의 일부만 무시하기

let mut setting_value = Some(5);
let new_setting_value = Some(10);

match (setting_value, new_setting_value) {
    // 두 Some값에 저장된 실제 값은 사용하지 않지만, 모두 Some 값을 가지고 있는지만 검사한다.
    (Some(_), Some(_)) => {
        println!("이미 설정된 값을 덮어쓸 수 없습니다.");
    }
    // 그 외의 경우: 둘 중 하나가 None
    _ => {
        setting_value = new_setting_value;
    }
}

println!("현재 설정: {:?}", setting_value);
// 한 패턴에서 여러 번 사용해서 특정 값을 무시
let numbers = (2, 4, 8, 16, 32);

match numbers {
    (first, _, third, _, fifth) => {
        println!("일치하는 숫자: {}, {}, {}", first, third, fifth)
    },
}


변수 이름을 _로 시작해 사용하지 않는 변수 무시하기

fn main() {
    let _x = 5;
    let y = 10; // y에 대해서만 경고가 출력된다.
}


let s = Some(String::from(""));

if let Some(_s) = s { // 변수 s의 값이 _s로 이동하게 되어서
    println!("문자열을 찾았습니다.");
}

println!("{:?}", s); // 변수 s를 더는 사용할 수 없다.
let s = Some(String::from(""));

if let Some(_) = s { // 바인딩 되지 않음
    println!("문자열을 찾았습니다.");
}

println!("{:?}", s); // 변수 s 사용 가능


..를 이용해 값의 나머지를 무시하기

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

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

match origin {
    Point { x, .. } => println!("x = {}", x),
}
let numbers = (2, 4, 8, 16, 32);

match numbers {
    (first, .., last) => {
        println!("first = {}, last = {}", first, last);
    },
}
let numbers = (2, 4, 8, 16, 32);

match numbers {
    (.., second, ..) => {
        println!("second = {}", second);
    },
}
// error


3-7. 매치 가드를 이용한 추가 조건

let num = Some(4);

match num {
    // 패턴만으로는 if x < 5를 표현할 수 없으므로 매치가드는 로직의 표현력을 한층 더 높여준다
    Some(x) **if x < 5** => println!("5보다 작은 값: {}", x),
    Some(x) => println!("{}", x),
    None => (),
}


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

    match x {
        Some(50) => println!("50"),
        // 새 변수 n을 생성해서 y(10)를 가리지 않고 값을 비교할 수 있다.
        // 매치가드 n == y는 패턴이 아니며 그래서 새로운 변수를 생성하지 않는다.
        Some(**n**) **if n == y** => println!("일치, y = {:?}", y),
        _ => println!("일치하지 않음, x = {:?}", x),
    }

    println!("결과: x = {:?}, y = {:?}", x, y);
}


let x = 4;
let y = false;

match x {
    **4 | 5 | 6** if y => println!("예"),
    _ => println!("아니오"),
}


3-8. @ 바인딩

enum Message {
    Helllo { id: i32 },
}

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

match msg {
    Message::Hello { id: id_variable @ 3...7 } => {
        // 값이 범위 패턴과 일치하는지 확인하는 동시에
        // 일치하는 값을 변수에 바인딩한다.
        println!("id를 범위에서 찾았습니다: {}", id_variable)
    },
    Message::Hello { id: 10...12 } => {
        // 패턴에 명시된 범위에 속하는지만 검사하며
        // id 필드의 실제 값을 가진 변수를 선언하지 않는다.
        println!("id를 다른 범위에서 찾았습니다.")
    },
    Message::Hello { id } => {
        // (구조체 필드를 간략하게 표기하는 문법을 사용해서)
        // 변수를 범위없이 선언했으므로 id라는 이름의 변수로 그 값을 사용할 수 있고,
        // id 필드값을 비교하지 않으며 어떤 값이든 이 패턴과 일치하게 된다.
        println!("다른 id {}를 찾았습니다.", id)
    },