10
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { // definition
    f(arg) + f(arg)
}

do_twice(|x| x + 1, 5) // call

这个函数接受闭包和函数指针。它采用函数指针作为参数类型。

什么时候我应该更喜欢这个而不是使用 trait 对象,比如&dyn Fn(i32) -> i32Box<dyn Fn(i32)-> i32>代替fn

fn do_twice(f: &dyn Fn(i32) -> i32, arg: i32) -> i32 { // definition
    f(arg) + f(arg)
}

do_twice(&|x| x + 1, 5) // call

或者

fn do_twice(f: Box<dyn Fn(i32) -> i32>, arg: i32) -> i32 { // definition
    f(arg) + f(arg)
}
4

2 回答 2

11

什么时候我应该更喜欢这个而不是使用 trait 对象

特征对象不是唯一的其他选择。正如@DarthKotik 指出的那样,接受fn指针将不允许捕获其环境的闭包,但是您可以只使用普通类型参数,Fn以接受函数和闭包,而无需装箱:

fn do_twice<F>(f: F, arg: i32) -> i32 
where
    F: Fn(i32) -> i32
{
    f(arg) + f(arg)
}

或者,等效地,但避免使用额外的类型变量:

fn do_twice(f: impl Fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}
于 2019-01-14T13:10:18.017 回答
10

fntype 是一个裸函数指针(https://doc.rust-lang.org/std/primitive.fn.html)。

它不适用于捕获环境的闭包,并且无法为您的花哨类型手动实现(例如impl Fn for MySuperType

因此,您的示例有效的唯一原因是它过于简单化了!

如果你让它更复杂一点,它将失败https://gist.github.com/rust-play/2167e73325daa1e2a179505209405917

于 2019-01-14T13:03:21.807 回答