为什么对实现 Fn 的类型的引用不被识别为可调用?

Why is a reference to a type that implements Fn not recognized as a callable?

即使 &T 被定义为实现 Fn 特性,编译器在将其作为可调用对象调用时也会拒绝它:

trait Trait {
    fn act(self);
}

//passes
fn test_ref_input_as_trait<'a, T>(t: &'a T)
where
    &'a T: Trait,
{
    t.act();
}

//fails
fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
where
    &'a T: Fn(),
{
    t();
}

//passes
fn test_input_as_fntrait<T>(t: T)
where
    T: Fn(),
{
    t();
}

编译器拒绝第二个函数的定义:

error[E0618]: expected function, found `&'a T`
  --> src/lib.rs:18:5
   |
14 | fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
   |                                     - `&'a T` defined here
...
18 |     t();
   |     ^^^ not a function

对于 nightly (1.32),错误消息替换为:

error[E0618]: expected function, found `&'a T`
  --> src/lib.rs:18:5
   |
14 | fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
   |                                     - `&'a T` defined here
...
18 |     t();
   |     ^--
   |     |
   |     call expression requires function

也许我遗漏了什么,但为什么编译器接受定义但不允许调用它?是我这边的句法缺陷导致它理解别的东西吗?

这可能是一个错误(例如,如果您将 &'a T 替换为 (&'a T,),它会起作用)。不过,您可以这样调用该函数:

fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
where
    &'a T: Fn(),
{
    (&t)();
}

但是由于 T: Fn() 自动暗示 &T: Fn(),像你上一个例子那样写会更容易也更惯用。

fn test_ref_input_as_fntrait<F: Fn()>(t: F) {
    t();
}

fn main() {
    test_ref_input_as_fntrait(&|| println!("it's okay!"));
}

有一个open issue (#42736) about this. However, the docs for Fn状态:

for any type F that implements Fn, &F implements Fn, too.

这意味着以下工作:

fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
where
    T: Fn(),
{
    t();
}