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

时间:2018-12-05 08:24:11

标签: rust traits 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

在每晚(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

也许我遗漏了一些东西,但是为什么编译器会接受该定义但不允许调用它?在我这方面的语法缺陷是否使它理解其他问题?

2 个答案:

答案 0 :(得分:4)

有一个open issue (#42736)。但是,docs for Fn状态:

  

对于任何实现F的类型Fn&F也实现Fn

这意味着可以进行以下操作:

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

答案 1 :(得分:3)

这可能是一个错误(例如,如果您将&'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!"));
}