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

콤비네이터: and_then

map()match 문을 단순화하기 위한 체인 가능한 방법으로 설명되었습니다. 하지만 Option<T>를 반환하는 함수에 map()을 사용하면 중첩된 Option<Option<T>>가 생성됩니다. 여러 호출을 함께 체인으로 연결하는 것은 혼란스러울 수 있습니다. 이때 다른 언어에서 flatmap으로 알려진 and_then()이라는 또 다른 콤비네이터가 등장합니다.

and_then()은 래핑된 값을 가지고 함수 입력을 호출하고 그 결과를 반환합니다. 만약 OptionNone이라면, 대신 None을 반환합니다.

다음 예제에서, cookable_v3()Option<Food>를 결과로 냅니다. and_then() 대신 map()을 사용했다면 Option<Option<Food>>를 얻었을 것이며, 이는 eat()에 대해 유효하지 않은 타입입니다.

#![allow(dead_code)]

#[derive(Debug)] enum Food { CordonBleu, Steak, Sushi }
#[derive(Debug)] enum Day { Monday, Tuesday, Wednesday }

// 우리는 스시를 만들 재료가 없습니다.
fn have_ingredients(food: Food) -> Option<Food> {
    match food {
        Food::Sushi => None,
        _           => Some(food),
    }
}

// 우리는 코르동 블뢰(Cordon Bleu)를 제외한 모든 것의 레시피를 가지고 있습니다.
fn have_recipe(food: Food) -> Option<Food> {
    match food {
        Food::CordonBleu => None,
        _                => Some(food),
    }
}

// 요리를 하려면 레시피와 재료가 모두 필요합니다.
// 우리는 이 로직을 `match`들의 체인으로 표현할 수 있습니다:
fn cookable_v1(food: Food) -> Option<Food> {
    match have_recipe(food) {
        None       => None,
        Some(food) => have_ingredients(food),
    }
}

// 이는 `and_then()`을 사용하여 더 간결하게 다시 작성될 수 있습니다:
fn cookable_v3(food: Food) -> Option<Food> {
    have_recipe(food).and_then(have_ingredients)
}

// 그렇지 않다면 `Option<Food>`를 얻기 위해 `Option<Option<Food>>`를 `flatten()`해야 할 것입니다:
fn cookable_v2(food: Food) -> Option<Food> {
    have_recipe(food).map(have_ingredients).flatten()
}

fn eat(food: Food, day: Day) {
    match cookable_v3(food) {
        Some(food) => println!("야호! {:?}에 우리는 {:?}를 먹게 되었어요.", day, food),
        None       => println!("오 이런. {:?}에는 못 먹는 건가요?", day),
    }
}

fn main() {
    let (cordon_bleu, steak, sushi) = (Food::CordonBleu, Food::Steak, Food::Sushi);

    eat(cordon_bleu, Day::Monday);
    eat(steak, Day::Tuesday);
    eat(sushi, Day::Wednesday);
}

참고:

클로저, Option, Option::and_then(), 그리고 Option::flatten()