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

타입 익명성

클로저는 자신을 감싸고 있는 스코프에서 변수를 간결하게 캡처합니다. 이것이 어떤 결과를 초래할까요? 분명히 결과가 있습니다. 클로저를 함수 파라미터로 사용할 때 제네릭이 왜 필요한지, 클로저가 어떻게 정의되는지를 통해 살펴보세요:

#![allow(unused)]
fn main() {
// `F`는 제네릭이어야 합니다.
fn apply<F>(f: F) where
    F: FnOnce() {
    f();
}
}

클로저가 정의될 때, 컴파일러는 내부에 캡처된 변수를 저장하기 위해 새로운 익명 구조체를 암시적으로 생성하며, 동시에 이 알 수 없는 타입에 대해 Fn, FnMut, 또는 FnOnce 트레이트 중 하나를 통해 기능을 구현합니다. 이 타입은 변수에 할당되어 호출될 때까지 저장됩니다.

이 새로운 타입은 알 수 없는 타입이므로, 함수에서 사용할 때는 제네릭이 필요합니다. 하지만 제약이 없는 타입 파라미터 <T>는 여전히 모호하므로 허용되지 않습니다. 따라서 클로저가 구현하는 Fn, FnMut, 또는 FnOnce 트레이트 중 하나로 바운딩하는 것이 그 타입을 지정하기에 충분합니다.

// `F`는 입력이 없고 아무것도 반환하지 않는 클로저를 위해
// `Fn`을 구현해야 합니다. 이는 정확히 `print`에 요구되는 사항입니다.
fn apply<F>(f: F) where
    F: Fn() {
    f();
}

fn main() {
    let x = 7;

    // `x`를 익명 타입으로 캡처하고 그에 대해 `Fn`을 구현합니다.
// 이를 `print`에 저장합니다.
    let print = || println!("{}", x);

    apply(print);
}

참고:

철저한 분석, Fn, FnMut, 그리고 FnOnce