fn apply<F>(f: F) where
F: FnOnce() {
f(); // statement, return value ()
}
fn apply_to_3<F>(f: F) -> i32 where
F: Fn(i32) -> i32 {
f(3) //expression
}
fn main() {
use std::mem;
let greeting = "hello"; //&str = Stack = Sized, str = Static = Sized
let mut farewell = "goodbye".to_owned(); //String = Heap = Unsized
let diary = || {
println!("I said {}.", greeting);
farewell.push_str("!!!");
println!("Then I screamed {}.", farewell);
println!("Now I can sleep. zzzzz");
mem::drop(farewell);
};
apply(diary);
let double = |x| 2 * x;
println!("3 doubled: {}", apply_to_3(double));
}
Fn
은 captured value를 레퍼런스 형태로 가져온다. &T
FnMut
는 captured value를 수정 가능한 레퍼런스로 가져온다. &mut T
FnOnce
는 captured value를 값 그대로 가져온다. T
fn apply<F>(f: F) where
F: FnOnce() {
f(); // statement, return value ()
}
위 함수를 이해하는데 시간이 조금 걸렸는데, 풀어서 설명하자면
f
를 인자로 받는데 이 때 f
는 함수이며, F
타입이다.
F
타입이라는 말은 FnOnce
타입이라는 뜻이고,
이 apply
함수는 인자로 받은 f
라는 함수를 실행시켜서 그 값을 리턴한다.
이제 메인 함수의 apply(diary)
를 보면 좀 더 쉽게 이해할 수 있을 것이다.
apply
함수는 FnOnce 타입 의 diary
라는 함수를 인자로 받아서 diary 함수를 실행시켜 그 값을 리턴한다. diary
함수는 Closure 로 마지막에 함수 밖에서 가져온 farewell
을 Drop하기 때문에 FnOnce 타입 이 되는 것이다. FnOnce 타입 은 variable을 가져와서 소비하기 때문에 다시 사용할 수 없다.
//&str = Stack = Sized, str = Static = Sized
//String = Heap = Unsized
이 부분도 중요하니 참고! Heap에 저장되는 String은 공간이 늘어날 수 있기 때문에 .push_str()
을 사용할 수 있었던 것이다.