2

Even if &T is defined as implementing the Fn trait, the compiler rejects it when invoking it is as a callable:

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();
}

The compiler rejects the definition of the second function with:

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

With nightly (1.32), the error message is replaced with:

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

Maybe I'm missing something, but why is the compiler accepting the definition but not allowing it to be invoked? Is it a syntactical shortcoming from my side that leads it to understand something else?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
vikram2784
  • 783
  • 7
  • 14
  • 1
    Afaik you can't have a reference to a function like that. You can say, that a function should live as long as `'a` with `fn foo<'a, T: Fn() + 'a>(t: T) { t() }` – hellow Dec 05 '18 at 08:34

2 Answers2

4

There is an open issue (#42736) about this. However, the docs for Fn state:

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

This means that the following works:

fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
where
    T: Fn(),
{
    t();
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
attdona
  • 17,196
  • 7
  • 49
  • 60
3

This is perhaps a bug (e.g. it works if you replace the &'a T by (&'a T,)). Nevertheless, you can call the function like this:

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

but since T: Fn() automatically implies &T: Fn(), it is easier and more idiomatic to just write like your last example.

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

fn main() {
    test_ref_input_as_fntrait(&|| println!("it's okay!"));
}
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005