Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

콤비네이터: map

matchOption을 처리하는 유효한 방법입니다. 하지만 특히 입력이 있을 때만 유효한 연산들의 경우, 과도한 사용은 지루할 수 있습니다. 이런 경우, 콤비네이터(combinators)를 사용하여 모듈식으로 제어 흐름을 관리할 수 있습니다.

Option에는 Some -> SomeNone -> None의 단순 매핑을 위한 콤비네이터인 map() 메서드가 내장되어 있습니다. 여러 개의 map() 호출을 체인으로 연결하여 훨씬 더 유연하게 사용할 수 있습니다.

다음 예제에서 process()는 간결함을 유지하면서 그 이전의 모든 함수들을 대체합니다.

#![allow(dead_code)]

#[derive(Debug)] enum Food { Apple, Carrot, Potato }

#[derive(Debug)] struct Peeled(Food);
#[derive(Debug)] struct Chopped(Food);
#[derive(Debug)] struct Cooked(Food);

// 음식을 껍질 벗깁니다. 음식이 없다면 `None`을 반환합니다.
// 그렇지 않으면 껍질을 벗긴 음식을 반환합니다.
fn peel(food: Option<Food>) -> Option<Peeled> {
    match food {
        Some(food) => Some(Peeled(food)),
        None       => None,
    }
}

// 음식을 썹니다. 음식이 없다면 `None`을 반환합니다.
// 그렇지 않으면 썬 음식을 반환합니다.
fn chop(peeled: Option<Peeled>) -> Option<Chopped> {
    match peeled {
        Some(Peeled(food)) => Some(Chopped(food)),
        None               => None,
    }
}

// 음식을 요리합니다. 여기서는 케이스 처리를 위해 `match` 대신 `map()`을 보여줍니다.
fn cook(chopped: Option<Chopped>) -> Option<Cooked> {
    chopped.map(|Chopped(food)| Cooked(food))
}

// 음식을 순서대로 껍질 벗기고, 썰고, 요리하는 함수입니다.
// 코드를 단순화하기 위해 `map()`을 여러 번 체인으로 연결합니다.
fn process(food: Option<Food>) -> Option<Cooked> {
    food.map(|f| Peeled(f))
        .map(|Peeled(f)| Chopped(f))
        .map(|Chopped(f)| Cooked(f))
}

// 먹기 전에 음식이 있는지 없는지 확인합니다!
fn eat(food: Option<Cooked>) {
    match food {
        Some(food) => println!("음~ 전 {:?}가 정말 좋아요", food),
        None       => println!("오 이런! 먹을 수 있는 게 아니었어요."),
    }
}

fn main() {
    let apple = Some(Food::Apple);
    let carrot = Some(Food::Carrot);
    let potato = None;

    let cooked_apple = cook(chop(peel(apple)));
    let cooked_carrot = cook(chop(peel(carrot)));
    // 이제 더 간단해 보이는 `process()`를 시도해 봅시다.
    let cooked_potato = process(potato);

    eat(cooked_apple);
    eat(cooked_carrot);
    eat(cooked_potato);
}

참고:

클로저, Option, Option::map()