개발_기록용

RUST 스터디[RUST vs C++] 12. Pattern Matching 본문

RUST 스터디

RUST 스터디[RUST vs C++] 12. Pattern Matching

나폴나폴 2024. 5. 13. 22:38
728x90

https://google.github.io/comprehensive-rust/pattern-matching.html

 

Pattern Matching - Comprehensive Rust 🦀

This segment should take about 1 hour. It contains: SlideDuration Matching Values10 minutes Destructuring Structs4 minutes Destructuring Enums4 minutes Let Control Flow10 minutes Exercise: Expression Evaluation30 minutes

google.github.io

12.1 Matching Values

각각을 살펴보면

 

#[rustfmt::skip]
fn main() {
    let input = 'x';
    match input {
        'q'                        => println!("Quitting"),
        'a' | 's' | 'w' | 'd'        => println!("Moving around"),    : or를 사용해 case 처리 가능.
        '0'..='9'                  => println!("Number input"),      : 0~9와 같이 범위 가능.
        key if key.is_lowercase() => println!("Lowercase: {key}"),   : 조건을 만족하면, key를 받아서 오른쪽에 써먹을 수 있음.
        _                          => println!("Something else"),    : 나머지가 Rust에선 _ *언더스코어 로 처리.
    }
}

✔ 안 다루는 부분이 있다면 오류가 남.
예를 들어 우리가 i32로 패턴매칭을 하면, -21억4천3백어쩌구 ~ 21억4천3백어쩌구를 다 커버해야 함!

12.2 Destructing Structs

패턴 매칭의 확장.

#[rustfmt::skip]
fn main() {
    let foo = Foo { x: (1, 2), y: 3 };
    match foo {
        Foo { x: (1, b), y } => println!("x.0 = 1, b = {b}, y = {y}"), : x가 첫번쨰는 1, 뒤에는 아무거나
        Foo { y: 2, x: i }   => println!("y = 2, x = {i:?}"), : y가 2고, x는 아무거나
        Foo { y, .. }        => println!("y = {y}, other fields were ignored"), : 나머지는 y만 받겠다.
    }

 

근데 위보다는 아래의 형태처럼, Enum 열거체와 패턴 매칭이 찰떡 궁합이다.

위에껀 해석이 필요하므로, 잘 안쓰임;;

 

12.3 Destructing Enums

*divide_in_two를 보면 리턴이 Result

=> 함수가 잘 작동했는가를 담음. Rust에서 첫 등장한 열거체.

 

이런식으로 열거체와 쓰이는 형태의 패턴매칭은 매우 많이 쓰임!


12.4 Let Control Flow

패턴매칭은 if문, while문과 같은 거랑 같이 쓰기엔 매우 귀찮음.

Rust에서 제시한 Control Flow를 보자.

fn sleep_for(secs: f32) {
    let dur = if let Ok(dur) = std::time::Duration::try_from_secs_f32(secs) { : 결과가 Ok 이면 거기서 dur를 꺼내서 let dur에 담고,
        dur
    } else {
        std::time::Duration::from_millis(500) : 결과가 Err이면 왼쪽을 let dur에 담겠다.
    };
    std::thread::sleep(dur);
    println!("slept for {:?}", dur);
}

 

이번엔 let, else.
fn hex_or_die_trying(maybe_string: Option<String>) -> Result<u32, String> { : Option.
    let s = if let Some(s) = maybe_string { : maybe_string이 String일 경우. 즉, Some일 경우.
        s
    } else { : maybe_string이 None인 경우.
        return Err(String::from("got None"));
    };

    let first_byte_char = if let Some(first_byte_char) = s.chars().next() {
        first_byte_char
    } else {
        return Err(String::from("got empty string"));
    };

    if let Some(digit) = first_byte_char.to_digit(16) {
        Ok(digit)
    } else {
        Err(String::from("not a hex digit"))
    }
}

 

Rust에서 Option은, 우리가 수능에서 영단어 공부할 때, 자주 등장하는 단어의 논리라면 별표 다섯개!
Rust의 대부분의 함수의 리턴 타입이 Option이고, 매우 중요.

Option. Rust에서 왜 등장했을까?

컴퓨터의 흑역사를 보면 IEEE 754가 있다.

얘 때문에, 0.1 * 10 = 1.0이 안 됨.

 

또 하나가 Null임. 이게 악의 근원.

참고로, Null이라는 값을 만든 사람이 있고, 그 사람은 지금 그걸 후회한다 함.

 

Null은 곧, 존재하지 않는다. 재밌죠?

그럼 undefined와 Null은 뭐가 다를까?

Null은 명시적으로 없다.. 그럼 undefined는 명시적이지 않은 것일까?

 

일단 이 Null의 "없다" 때문에 생기는게 NullPointException같은 것이다.

그래서, Rust에선 Null이 없다.

 

근데 생각해보면, 우리가 Null이 없으면 불편할 때가 분명히 있다.

[10, 20, 30] 배열에서 우리가 34를 찾는 함수를 쓰면, 보통은 Null을 반환할 텐데 그게 불가능.

 

그럼, Null을 쓰기는 싫은데 Nullable함을 나타내야 할 상황이 생기는 것임.

그래서, Option이 나왔다.

 

Option은 Some(T)와 None으로 나뉜다.

Some은 Null이 아닌 것, None은 원래 쓰이던 Null인 것.

 

그럼 위의 사례처럼, while의 조건으로 name의 각 값을 pop으로 꺼내올 때,

빈게 있으면 pop이 안되어서 None일 텐데, 그럼 while문이 끝나야 함. Some이 아니므로

위와 같은 형태로 만들 수가 있다.

반응형
Comments