函数指针与Fn特征对象

时间:2019-01-14 12:45:13

标签: function rust closures traits trait-objects

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

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

此函数接受闭包和函数指针。它以函数指针作为参数类型。

与使用&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)
}

2 个答案:

答案 0 :(得分:5)

  

什么时候比使用特征对象更合适

特质对象不是唯一的其他选择。正如@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)
}

答案 1 :(得分:2)

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

它不能与捕获环境的闭包一起使用,并且不能为您喜欢的类型(例如impl Fn for MySuperType)手动实现

所以您的示例起作用的唯一原因是事实,它过于简化了!

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