Closure traits
闭包或 lambda 表达式具有无法命名的类型。不过,它们会 实现特殊的 Fn
, FnMut
和 FnOnce
特征:
The special types fn(..) -> T
refer to function pointers - either the address of a function, or a closure that captures nothing.
fn apply_and_log( func: impl FnOnce(&'static str) -> String, func_name: &'static str, input: &'static str, ) { println!("Calling {func_name}({input}): {}", func(input)) } fn main() { let suffix = "-itis"; let add_suffix = |x| format!("{x}{suffix}"); apply_and_log(&add_suffix, "add_suffix", "senior"); apply_and_log(&add_suffix, "add_suffix", "appendix"); let mut v = Vec::new(); let mut accumulate = |x| { v.push(x); v.join("/") }; apply_and_log(&mut accumulate, "accumulate", "red"); apply_and_log(&mut accumulate, "accumulate", "green"); apply_and_log(&mut accumulate, "accumulate", "blue"); let take_and_reverse = |prefix| { let mut acc = String::from(prefix); acc.push_str(&v.into_iter().rev().collect::<Vec<_>>().join("/")); acc }; apply_and_log(take_and_reverse, "take_and_reverse", "reversed: "); }
An Fn
(e.g. add_suffix
) neither consumes nor mutates captured values. It can be called needing only a shared reference to the closure, which means the closure can be executed repeatedly and even concurrently.
An FnMut
(e.g. accumulate
) might mutate captured values. The closure object is accessed via exclusive reference, so it can be called repeatedly but not concurrently.
If you have an FnOnce
(e.g. take_and_reverse
), you may only call it once. Doing so consumes the closure and any values captured by move.
FnMut
是 FnOnce
的子类型。Fn
是 FnMut
和 FnOnce
的子类型。也就是说,您可以在任何 需要调用 FnOnce
的地方使用 FnMut
,还可在任何需要调用 FnMut
或 FnOnce
的地方 使用 Fn
。
When you define a function that takes a closure, you should take FnOnce
if you can (i.e. you call it once), or FnMut
else, and last Fn
. This allows the most flexibility for the caller.
In contrast, when you have a closure, the most flexible you can have is Fn
(which can be passed to a consumer of any of the 3 closure traits), then FnMut
, and lastly FnOnce
.
The compiler also infers Copy
(e.g. for add_suffix
) and Clone
(e.g. take_and_reverse
), depending on what the closure captures. Function pointers (references to fn
items) implement Copy
and Fn
.