C.W.K.
Stream
Lesson 04 of 06 · published

클로저 — 캡처하는 함수

~11 min · collections, closures, fn-traits, move

Level 0Rust 호기심러
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

클로저는 정의된 스코프의 변수를 캡처 할 수 있는 익명 함수야. 이터레이터 체인의 접착제고, 함수형 스타일 Rust 가 그렇게 깔끔하게 읽히는 이유야.

문법

클로저는 |인자| 본문 이야: |x| x + 1x 를 받아 x + 1 을 반환해. 함수와 달리 주변 스코프의 변수를 파라미터로 받지 않고 쓸 수 있어 — 캡처 하거든. 컴파일러가 쓰는 방식에서 인자랑 반환 타입을 추론해.

캡처하는 세 방법

클로저는 각 변수를 가능한 가장 덜 제약적인 방식으로 캡처해: 읽기만 하면 불변 참조로, 수정하면 가변 참조로, 소유해야 하면 값으로. 이 세 모드가 세 trait 에 대응해 — Fn (캡처 읽음), FnMut (캡처 변형), FnOnce (캡처 소비, 한 번 호출 가능). 이름 붙일 일은 드물어; 컴파일러가 고르고, 클로저를 받는 함수가 뭘 받을지 선언해.

Fn trait 은 캡처한 변수에 적용된 소유권 규칙이야. 읽기 전용 캡처는 공유 borrow (Fn); 변형 캡처는 가변 borrow (FnMut); 소비 캡처는 move (FnOnce). Borrowing 트랙의 그 aliasing 로직이 클로저가 어느 trait 을 구현할지 정해.

move 클로저

클로저 앞에 move 를 붙이면 캡처하는 모든 걸 소유하게 강제해: move |x| x + base. 클로저가 현재 스코프보다 오래 살 때 필수야 — 스레드에 넘기거나, 반환하거나, 저장할 때. Concurrency 트랙이 데이터를 스레드에 안전하게 건네려고 move 클로저에 기대.

Code

Fn, FnMut, 그리고 move 클로저·rust
fn main() {
    let base = 10;
    let add_base = |x: i32| x + base; // `base` 를 참조로 캡처 (읽기만)
    println!("{}", add_base(5));      // 15

    let mut count = 0;
    let mut tick = || { count += 1; }; // FnMut: `count` 를 가변으로 캡처
    tick();
    tick();
    println!("{count}");              // 2

    // move: 클로저가 캡처하는 걸 소유함
    let owned = String::from("hi");
    let consume = move || println!("{owned}"); // 이제 `owned` 를 소유
    consume();
}

External links

Exercise

스코프에서 multiplier 를 캡처해 인자를 그걸로 곱하는 클로저를 써봐. 그다음 String 을 캡처해 출력하는 move 클로저를 쓰고, 그 뒤로 원본 String 을 더는 못 쓰는 걸 확인해. move 가 두 번째 클로저를 왜 정신적으로 FnOnce 스럽게 만들어?
Hint
move 후엔 클로저가 String 을 소유해서 바깥 스코프가 못 써. 값으로-캡처는 Ownership 트랙의 그 move 시맨틱이야 — move 는 그걸 클로저의 환경에 적용할 뿐이야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.