Rust match control flow Construct

고승우·2023년 7월 4일
0
post-thumbnail

Match Cotrol Flow Construct

Rust에는 매칭되는 pattern에 따라 코드가 실행되도록 하는 좋은 control flow construct match가 있다. 동전을 매칭하는 경우를 생각해보자.

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

if문을 사용한 경우에는 bool 타입을 반환해야 하지만, match를 사용하는 경우에는 위에서 정의한 enum 타입처럼 모두 같은 타입을 갖고 있어야 한다. 각 arm은 표현식이며, 그 결과값은 match 표현식의 전체 반환 값이 된다.

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("Lucky penny!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

Patterns That Bind to Values

match arm(갈래)의 또다른 유용한 특징은 패턴에 매칭된 값을 값에 바인딩할 수 있다는 것이다. enum 변형의 하나를 바꿔 데이터를 가져 보자. 1998 ~ 2008까지 미국은 한쪽에 50개 주마다 다른 디자인의 quarter를 주조했다.

#[derive(Debug)] // so we can inspect the state in a minute
enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

친구가 모든 50개 주 quarter를 모은다고 상상해보자. 우리는 coin type 별로 정렬하고, 또한 각 quarter도 state와 결합된 이름을 call out(호출)할 것이다. 이 match 표현식에서 Coin::Quarter와 결합할 state 변수를 추가한다. 만약 Coing::Quarter와 match될 경우, quarter의 상태로 state가 bind될 것이다.

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("State quarter from {:?}!", state);
            25
        }
    }
}

Matching with Option<T>

이전에 Option<T>를 사용할 때 Some 케이스에서 내부 T 값을 얻고 싶었습니다. 또한 우리는 match를 사용해 Option<T>를 다룰 수 있따. 우리는 Option<T>의 변형을 비교할 것이지만 match 표현식이 작동하는 방식은 동일하게 유지된다.

    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);

plus_one(five)를 호출하면 변수 xSome(5) 값을 갖고 함수 안으로 들어가게 되고, 각 match arm에서 비교하게 된다.

Matches Are Exhaustive

match 표현식은 가능한 모든 경우를 다뤄야 한다. 아래와 같이 plus_one 함수를 만들면 버그를 갖고 컴파일되지 않는다. 그렇기 때문에 철저하게 가능한 모든 경우를 커버해야 한다.

    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            Some(i) => Some(i + 1),
        }
    }
$ cargo run
   Compiling enums v0.1.0 (file:///projects/enums)
error[E0004]: non-exhaustive patterns: `None` not covered

Catch-all Patterns and the _Placeholder

enum을 사용하면서 몇가지 경우에는 special action을 나머지는 default action을 취하고 싶을 때가 있다. 주사위를 예시로 들었을 때, 아래와 같이 구현할 수 있다. 러스트에는 _라는 특별한 패턴이 존재한다. bind 되지 않은 value와 매칭해주는 특별한 패턴이다.

    let dice_roll = 9;
    match dice_roll {
        3 => add_fancy_hat(),
        7 => remove_fancy_hat(),
        _ => reroll(),
    }

    fn add_fancy_hat() {}
    fn remove_fancy_hat() {}
    fn reroll() {}

3 혹ㅇ느 7 외ㅢㅇ 값이 들어온 경우 아무 일도 일어나지 않을 때는 아래와 같이 코드를 작성할 수 있따.

    let dice_roll = 9;
    match dice_roll {
        3 => add_fancy_hat(),
        7 => remove_fancy_hat(),
        _ => (),
    }

    fn add_fancy_hat() {}
    fn remove_fancy_hat() {}

empty tuple에 관해서는 링크에서 더 자세한 내용을 확인할 수 있다.

profile
٩( ᐛ )و 

0개의 댓글