看起来 Rust 中的函数可以将闭包作为参数Box:
closure: Box<dyn Fn()>
Run Code Online (Sandbox Code Playgroud)
或作为&impl:
closure: &impl Fn()
Run Code Online (Sandbox Code Playgroud)
两者有何区别?有没有比其他更值得推荐的?
Box<dyn Fn()>在堆上分配,并使用动态调度。
在堆上分配比堆栈分配更昂贵 - 必须在运行时为对象分配内存。
动态调度意味着要运行的实际函数是在运行时确定的,而不是在编译时确定。
impl Fn()当在函数参数位置使用时,相当于使用泛型参数。例如,这个:
foo(f: impl Fn())
Run Code Online (Sandbox Code Playgroud)
相当于:
foo<F: Fn()>(f: F)
Run Code Online (Sandbox Code Playgroud)
像这样定义,Rust 将使用静态调度。这意味着它将在编译时为传递给它的每个具体类型生成一个函数版本。这是用更大的编译代码大小来换取更低的运行时成本,因为它不需要弄清楚在运行时调用哪个函数。
大多数时候,编写一个采用通用形式impl Fn()或等效通用形式的函数是首选,因为它可以带来更好的运行时性能。
盒装闭包也实现了Fn()这样的效果:
fn foo(f: impl Fn()) {
f();
}
fn main() {
let f = Box::new(|| println!("Hello"));
foo(f);
foo(|| println!("world"));
}
Run Code Online (Sandbox Code Playgroud)
编写要接受的函数impl Fn()是最灵活的,因为它可以采用任一形式的参数。
impl Fn()请注意,在返回位置中使用是不同的。
还要注意Box<dyn Fn()>和impl Fn()均按值传递,因此它们转移了闭包的所有权。&impl Fn()通过引用传递 - 等效的盒装闭包是&Box<dyn Fn()>.