我应该按值还是按引用传递函数对象?

Cli*_*ton 8 rust

似乎有两种方法可以将函数作为参数传递,而不进行动态分配:

  1. &impl Fn(TIn) -> TOut // By reference
  2. impl Fn(TIn) -> TOut // By value

假设函数是纯函数(即可以多次调用),我最初的想法是最好的方法是通过引用传递。这意味着一个函数对象可以多次使用(因为所有权不会转移),在更常见的情况下,它只是一个匿名闭包,应该优化引用的间接引用,因为编译器完全知道函数本身(因此可以内联)。

但是,Option::map例如,我注意到按值传递了它的关闭,这让我觉得也许我做错了什么。

我应该按值还是按引用传递函数对象?如果两种方法都没有明确的答案,我应该考虑哪些因素?

Mat*_* M. 7

TL; DR:您应该使用F: Fn() -> ()impl Fn() -> ()作为参数。

Fn

正如@Bubletan提到在他们的答案,关键的一点是,Fn自动执行&F,如果F工具Fn

impl<'_, A, F> Fn<A> for &'_ F
where
    F: Fn<A> + ?Sized,
Run Code Online (Sandbox Code Playgroud)

结果是:

  • foo(f: impl Fn() -> ())可以同时foo(callable)或调用foo(&callable)
  • foo(f: &impl Fn() -> ()) 强制呼叫者使用foo(&callable)和禁止foo(callable)

通常,最好在被呼叫者有缺点时将选择权留给呼叫者,因此应首选第一种形式。

FnMut

同样的逻辑适用于FnMut,它也自动地实现&mut F如果F工具FnMut

impl<'_, A, F> FnMut<A> for &'_ mut F
where
    F: FnMut<A> + ?Sized, 
Run Code Online (Sandbox Code Playgroud)

因此,还应该在参数中通过值传递该参数,从而让调用者可以选择是否更喜欢foo(callable)foo(&mut callable)

FnOnce

存在与保持一致的参数,FnOnce只能通过值传递,这再次指向按值获取Fn*家庭参数的方向。