러스트에서 클로저는 외부 가시성 영역에서 변수를 "캡처"할 수 있는 익명 함수입니다. 문법:
let add = |a: i32, b: i32| a + b;
러스트에는 세 가지 유형의 클로저가 있습니다(변수 캡처 방식에 따라 다름):
&T)를 캡처하며, 환경을 변경하지 않고 여러 번 호출할 수 있습니다.&mut T)를 캡처하며, 호출 시 클로저 내의 데이터를 변경할 수 있습니다.T).러스트는 필요한 유형을 자동으로 결정하지만, 명시적으로 지정할 수도 있습니다.
차이점 예:
let s = String::from("hello"); // FnOnce let consume = move || println!("{}", s); // 호출 후 s는 더 이상 접근할 수 없음
왜 move 키워드를 가진 클로저가 FnOnce가 아니라 Fn 또는 FnMut가 될 수 있을까요?
답변: move 키워드는 변수를 소유권으로 이동시켜 캡처하지만, 클로저 내부의 데이터가 변경되지 않고 파괴되지 않는 경우, 클로저는 Fn/FnMut와 호환성을 유지합니다. 예:
let s = String::from("abc"); let c = move || println!("String: {}", s); // c: impl Fn() c();
c는 여러 번 호출할 수 있습니다: s의 값이 클로저에 복사되었지만 파괴되지는 않았습니다.
이야기
데이터 스트림 프로젝트에서 초보 러스트 개발자는 move 없이 클로저를 작성하고 다른 스레드에 전달하려고 했습니다. 그 결과 컴파일러는 outlived borrow에 대해 경고하며, 라이프타임과 move의 세부 사항을 긴급히 이해해야 했습니다.
이야기
클로저 내부에서 가변성을 도입했지만, 유형을 FnMut로 변경하지 않아 iterator 사용 시 "mismatched types" 오류가 발생했습니다.
이야기
큰 배열을 처리할 때 클로저가 move로 전체 컬렉션을 가져가 소유권을 이동시켜, 바깥쪽 코드가 첫 번째 반복 이후 데이터에 접근할 수 없게 되면서 moved value에 접근하려고 시도하게 되었습니다.