NeuroWhAI의 잡블로그

[Rust] do-while 본문

개발 및 공부/언어

[Rust] do-while

NeuroWhAI 2020. 5. 3. 14:52


MS가 최근 winrt를 Rust로 구현하여 공개했는데 그 예제로 지뢰찾기가 있다.
지뢰찾기 코드를 구경하던 중 아래와 같은 코드(#)를 발견.

Rust는 블럭({ ... })도 식으로 평가하기 때문에 while의 조건식에 블럭을 사용할 수 있는 것을 이용한 꼼수이다.

while {
    수행할 내용들;
    ...
    조건식
} { /* 빈 실제 실행문 */ }

찾아보니 거의 6년전(#)에 나온 꼼수인 듯하다.
근데 사실 보기에 그리 좋진 않다.
간단한 매크로를 만들면 좀 더 보기 괜찮아진다.

macro_rules! do_while {
    ($x:block, $y:expr) => {{
        while {
            $x;
            $y
        } {}
    }};
}

fn main() {
    let mut i = 0;
    do_while!({
        i += 1;
    }, i < 10);
    println!("i: {}", i);
}

근데 보기엔 이래도 조건식이기 때문에 break, continue를 쓸 수 없다.
아래와 같이 수정해주면 사용 가능하게 만들 수 있다.

macro_rules! do_while {
    ($x:block, $y:expr) => {{
        loop {
            $x;
            if !$y {
                break;
            }
        }
    }};
}

fn main() {
    let mut i = 0;
    do_while!({
        i += 1;
        if i == 5 {
            break;
        }
    }, i < 10);
    println!("i: {}", i);
}

하지만 이것도 break에서 값을 반환할 수가 없다는 단점이 있다.
아래와 같이 또 수정해주면 가능은 한데 가독성이 떨어진다.

macro_rules! do_while {
    ($x:block, $y:expr) => {{
        loop {
            $x;
            if !$y {
                break;
            }
        }
    }};
    ($x:block return $z:expr, $y:expr) => {{
        loop {
            $x;
            if !$y {
                break $z;
            }
        }
    }};
}

fn main() {
    let mut i = 0;
    let z = do_while!({
        i += 1;
        if i == 5 {
            break 42;
        }
    } return 0, i < 10);
    println!("i: {}", i);
    println!("z: {}", z);
}

return 대신 뭐 '=>'를 쓴다거나 다른 기호, 단어를 쓰면 좀 나아질지도 모르겠다.
사실 제일 좋은 건 로직을 잘 분석해서 while이나 loop로 대체하는 것이긴 하다..

그리고 이렇게 do-while을 쓸 일이 있을진 모르겠다.
지뢰찾기도 그렇고 찾아보면 do-while이 있는 언어의 코드를 Rust로 포팅할 때 많이들 찾는 것 같다.



Comments