8.2.2 As input parameters

Rust는 대부분 타입 주해 없이 즉각적으로 변수를 어떻게 캡쳐할 지를 정하게 되지만, 이 모호성은 함수를 작성할 때는 허용되지 않는다. 클로저를 입력 매개 변수로 취할 때, 클로저의 전체 타입은 몇 가지 trait들을 사용하여 주해된다. 제약이 적은 순서대로, 다음과 같다:

  • Fn: 클로저는 참조로 획득 (&T)
  • FnMut: 클로저는 가변참조로 획득 (&mut T)
  • FnOnce: 클로저는 값으로 획득 (T)

가변 변수에 기초하여 컴파일러는 가능한한 최소한의 제한적인 방법으로 변수를 캡쳐 할 것이다.

예를 들어, 매개 변수를 FnOnce로 생각해보자. 이것은 클로저가 아마도 &T, &mut T, 혹은 T로 캡쳐할 수 있음을 나타내지만 궁극적으로는 컴파일러가 캡쳐될 변수가 클로저에서 사용되는 방식에 따라 선택한다.

이것은 이동이 가능하다면, 어떤 타입으로 대여하는 것도 가능해야 하기 때문이다. 주의할 점은 역의 경우는 참이 아니다. 만약 매개변수가 Fn으로 주해되었다면 캡쳐되는 변수로 &mut T 혹은 T는 허용되지 않는다.

다음에 예제에서, Fn, FnMut, 그리고 FnOnce간에 사용 방식을 바꾸는 시도가 어떤 결과를 발생시키는지 확인해보자:

//클로저를 인자로 취하고 그를 호출하는 함수.
fn apply<F>(f: F) where
    // 클로저는 입력을 받지 않고 아무것도 반환하지 않는다.
    F: FnOnce() {
    // ^ TODO: 위를 `Fn`이나 `FnMut`로 변경해보세요.

    f()
}

// 클로저를 취하고 `i32`를 반환하는 함수
fn apply_to_3<F>(f: F) -> i32 where
    // 클로저는 `i32`를 취하고 `i32`를 반환한다.
    F: Fn(i32) -> i32 {

    f(3)
}

fn main() {
    use std::mem;

    let greeting = "hello";
    // 비-복사 유형.
    let mut farewell = "goodbye".to_owned();

    // 2개의 변수를 캡쳐한다 : `greeting`은 참조로 `farewell`은 값으로.
    let diary = || {
        // `greeting`은 참조에 의하므로 `Fn`이 필요하다.
        println!("I said {}.", greeting);

        // 변경은 `farewell`을 가변참조로 캡쳐되게 강제한다.
        // 여기서는 `FnMut`이 필요하다. 
        farewell.push_str("!!!");
        println!("Then I screamed {}.", farewell);
        println!("Now I can sleep. zzzzz");

        // 수동으로 drop을 호출하면 `farewell`을 값으로 캡쳐되도록 강제한다.
        // 여기서는 `FnOnce`가 요구된다. 
        mem::drop(farewell);
    };

    // 클로저를 적용하는 함수를 호출한다.
    apply(diary);
    // `double`은 `apply_to_3` trait의 범위를 만족시킨다.
    let double = |x| 2 * x;

    println!("3 doubled: {}", apply_to_3(double));
}

See also:

std::mem::drop, Fn, FnMut, and FnOnce

results matching ""

    No results matching ""