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

Option 풀기와 기본값

OptionNone일 때 이를 풀고 기본값으로 돌아가는 방법은 여러 가지가 있습니다. 우리의 필요에 맞는 것을 선택하려면 다음을 고려해야 합니다:

  • 조급한(eager) 평가가 필요한가요, 아니면 느긋한(lazy) 평가가 필요한가요?
  • 원래의 빈 값을 그대로 두어야 하나요, 아니면 그 자리에서 수정해야 하나요?

or()은 체인 가능하며, 조급하게 평가하고, 빈 값을 그대로 유지합니다.

or()은 체인 가능하며 다음 예제에서 보듯 인자를 조급하게 평가합니다. or의 인자들은 조급하게 평가되기 때문에, or에 전달된 변수는 이동(move)된다는 점에 유의하세요.

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let apple = Some(Fruit::Apple);
    let orange = Some(Fruit::Orange);
    let no_fruit: Option<Fruit> = None;

    let first_available_fruit = no_fruit.or(orange).or(apple);
    println!("first_available_fruit: {:?}", first_available_fruit);
    // first_available_fruit: Some(Orange)

    // `or`는 인자를 이동시킵니다.
    // 위 예제에서 `or(orange)`가 `Some`을 반환했으므로 `or(apple)`은 호출되지 않았습니다.
    // 하지만 `apple`이라는 이름의 변수는 상관없이 이동되었으며, 더 이상 사용할 수 없습니다.
    // println!("Variable apple was moved, so this line won't compile: {:?}", apple);
    // TODO: 위 줄의 주석을 해제하여 컴파일러 에러를 확인해 보세요.
}

or_else()는 체인 가능하며, 느긋하게 평가하고, 빈 값을 그대로 유지합니다.

또 다른 대안은 or_else를 사용하는 것입니다. 이 역시 체인 가능하며 다음 예제에서 보듯 느긋하게 평가합니다:

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let no_fruit: Option<Fruit> = None;
    let get_kiwi_as_fallback = || {
        println!("키위를 대체값으로 제공함");
        Some(Fruit::Kiwi)
    };
    let get_lemon_as_fallback = || {
        println!("레몬을 대체값으로 제공함");
        Some(Fruit::Lemon)
    };

    let first_available_fruit = no_fruit
        .or_else(get_kiwi_as_fallback)
        .or_else(get_lemon_as_fallback);
    println!("first_available_fruit: {:?}", first_available_fruit);
    // 키위를 대체값으로 제공함
    // first_available_fruit: Some(Kiwi)
}

get_or_insert()는 조급하게 평가하며, 빈 값을 그 자리에서 수정합니다.

Option에 값이 포함되도록 보장하기 위해, 다음 예제에서 보듯 get_or_insert를 사용하여 대체값으로 그 자리에서 수정할 수 있습니다. get_or_insert는 파라미터를 조급하게 평가하므로, apple 변수는 이동된다는 점에 유의하세요.

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let mut my_fruit: Option<Fruit> = None;
    let apple = Fruit::Apple;
    let first_available_fruit = my_fruit.get_or_insert(apple);
    println!("first_available_fruit is: {:?}", first_available_fruit);
    println!("my_fruit is: {:?}", my_fruit);
    // first_available_fruit is: Apple
    // my_fruit is: Some(Apple)
    //println!("apple이라는 이름의 변수는 이동되었습니다: {:?}", apple);
    // TODO: 위 줄의 주석을 해제하여 컴파일러 에러를 확인해 보세요.
}

get_or_insert_with()는 느긋하게 평가하며, 빈 값을 그 자리에서 수정합니다.

대체할 값을 명시적으로 제공하는 대신, 다음과 같이 get_or_insert_with에 클로저를 전달할 수 있습니다:

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let mut my_fruit: Option<Fruit> = None;
    let get_lemon_as_fallback = || {
        println!("레몬을 대체값으로 제공함");
        Fruit::Lemon
    };
    let first_available_fruit = my_fruit
        .get_or_insert_with(get_lemon_as_fallback);
    println!("first_available_fruit is: {:?}", first_available_fruit);
    println!("my_fruit is: {:?}", my_fruit);
    // 레몬을 대체값으로 제공함
    // first_available_fruit is: Lemon
    // my_fruit is: Some(Lemon)

    // Option에 값이 있으면 변경되지 않은 채로 유지되며, 클로저는 호출되지 않습니다.
    let mut my_apple = Some(Fruit::Apple);
    let should_be_apple = my_apple.get_or_insert_with(get_lemon_as_fallback);
    println!("should_be_apple is: {:?}", should_be_apple);
    println!("my_apple is unchanged: {:?}", my_apple);
    // 출력은 다음과 같습니다. `get_lemon_as_fallback` 클로저가 호출되지 않았음에 유의하세요.
    // should_be_apple is: Apple
    // my_apple is unchanged: Some(Apple)
}

참고:

클로저(closures), get_or_insert, get_or_insert_with, 이동된 변수(moved variables), or, or_else