【问题标题】:What's the practical difference between fn item and fn pointer?fn 项和 fn 指针之间的实际区别是什么?
【发布时间】:2021-02-02 21:28:54
【问题描述】:
fn func(_: i64) -> bool {
    true
}

fn func_of_func(callback: &fn(i64) -> bool, arg: i64) -> bool {
    (*callback)(arg)
}

fn main() {
    let is_positive = &func;
    println!("{}", func_of_func(is_positive, 8));
    println!("{}", func_of_func(is_positive, 8));
}

这不能编译:

error[E0308]: mismatched types
 --> src/main.rs:9:33
  |
9 |     println!("{}", func_of_func(is_positive, 8));
  |                                 ^^^^^^^^^^^ expected fn pointer, found fn item
  |
  = note: expected reference `&fn(i64) -> bool`
             found reference `&fn(i64) -> bool {func}`

为什么当我传递一个指针而不是fn时会出现这个错误?我想知道使用fn 和指向fn 的指针之间的实际区别。

【问题讨论】:

    标签: rust callback function-pointers


    【解决方案1】:

    fn(i64) -> boolalready a function pointer,所以&fn(i64) -> bool 是对函数指针的引用。因为函数指针是Copy,所以你永远不应该写这个。

    如果您正在编写一个将类似函数的东西作为参数的函数,您通常应该使用泛型(或impl Fn,如Mike Graham's answer,意思相同):

    fn func_of_func<F: FnOnce(i64) -> bool>(callback: F, arg: i64) -> bool {
        callback(arg)
    }
    

    这意味着当你用func这样的函数项调用func_of_func时,callback将被编译为直接函数调用而不是函数指针,这样更便于编译器优化。

    如果不能将函数设为泛型(可能是因为它是对象安全 trait 的成员),您通常应该使用 trait 对象,它允许调用者传递闭包:

    fn func_of_func(callback: &dyn Fn(i64) -> bool, arg: i64) -> bool { ... }
    fn func_of_func(callback: &mut dyn FnMut(i64) -> bool, arg: i64) -> bool { ... }
    // using `FnOnce` requires boxing
    fn func_of_func(callback: Box<dyn FnOnce(i64) -> bool>, arg: i64) -> bool { ... }
    

    函数指针应该只在函数绝对不能捕获任何东西时使用。它们对于使用 C 的 FFI 非常有用,并且作为泛型结构中 PhantomData 的类型参数。

    参考文献

    【讨论】:

      【解决方案2】:

      你应该可以解决这个问题

      fn func_of_func(callback: &fn(i64) -> bool, arg: i64) -> bool {
          (*callback)(arg)
      }
      
      fn main() {
          let is_positive = func;
          println!("{}", func_of_func(&is_positive, 8));
          println!("{}", func_of_func(&is_positive, 8));
      }
      

      或者更直接的方法是不添加间接级别

      fn func_of_func(callback: fn(i64) -> bool, arg: i64) -> bool {
          callback(arg)
      }
      
      fn main() {
          let is_positive = func;
          println!("{}", func_of_func(is_positive, 8));
          println!("{}", func_of_func(is_positive, 8));
      }
      

      更常见的是使用Fn trait,它的好处是允许闭包和函数

      fn func(x: i64) -> bool {
          true
      }
          
      fn func_of_func(callback: impl FnOnce(i64) -> bool, arg: i64) -> bool {
          callback(arg)
      }
      
      fn main() {
          let is_positive = func;
          println!("{}", func_of_func(is_positive, 8));
          println!("{}", func_of_func(is_positive, 8));
      }
      

      【讨论】:

        猜你喜欢
        • 2010-11-29
        • 2012-11-16
        • 1970-01-01
        • 2022-07-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-01
        • 2010-09-23
        相关资源
        最近更新 更多