16.2.1 Combinators: map

matchOption들을 처리하기 위한 유용한 메소드이다. 하지만 결국엔 복잡한 사용 방법에 지치게 될 것이다. 특히 입력 값을 검증하는 경우가 그렇다. 이 경우, 연결자(combinators)를 통해 모듈 방식으로 제어 흐름을 권리할 수 있다.

Optionmap()이란 내장 메소드가 있고, 연결자는 Some -> Some 그리고 None -> None으로 간단히 매핑하기 위해 사용한다. 다수의 map()호출을 연결해 사용하여 더 높은 유연성을 확보할 수 있다.

다음 예제에서 process()는 이전의 모든 함수를 함축하여 대체한다.

Run
#![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,
    }
}

// 음식 요리하기. 여기서는 보여주기 용으로 `map()`을 `match`대신 사용해 처리한다.
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!("Mmm. I love {:?}", food),
        None       => println!("Oh no! It wasn't edible."),
    }
}

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);
}

See also:

closures, Option, Option::map()

results matching ""

    No results matching ""