【问题标题】:function pointer vs Fn trait object [duplicate]函数指针与 Fn 特征对象 [重复]
【发布时间】:2019-01-14 12:45:13
【问题描述】:
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)
}

【问题讨论】:

  • 感谢您澄清了我的疑问。 fn 类型参数只能接受不捕获环境的闭包所以,当没有这样的约束时应该使用 trait 对象
  • 供参考(除了答案之外):RFC 1558 建议自动强制不将其环境捕获到 fn 指针的闭包。感谢这个 RFC,您的示例可以正常工作(可能出乎意料)。

标签: function rust closures traits trait-objects


【解决方案1】:

什么时候我应该更喜欢这个而不是使用 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)
}

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-02-12
      • 1970-01-01
      • 2019-01-21
      • 2017-06-29
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      • 2019-03-01
      • 1970-01-01
      相关资源
      最近更新 更多