3

Consider following code

async fn main_call(&self) -> Result<()> 
{
   let _list = self.sub_function(/*what to pass here?*/).await;
   // do something with the result

   Ok(())
}

async fn sub_function<P, F>(&self, f : Option<F>) -> Result<Vec<P>> 
   where 
     F : FnOnce(P) -> bool, 
     P : Clone
{

    // do something, and return a value
    // the `Vec::new()` is just here for demonstration purposes
    Ok(Vec::new())
}

What shall I pass as value to sub_function, if I don't want to pass a closure? If I pass None, the compiler complains:

type inside `async fn` body must be known in this context E0698 cannot infer type for type parameter `T`
 declared on the enum `Option` Note: the type is part of the `async fn` body because of this `await`

The complaint is obvious, but I'm not sure what I shall pass. None::<FnOnce(12)->bool) does not work.

expected a `std::ops::FnOnce<(&_,)>` closure, found `dyn std::ops::FnOnce(u32) -> bool` 
E0277 expected an `FnOnce<(&_,)>` closure, found `dyn std::ops::FnOnce(u32) -> bool` 
Help: the trait `std::ops::FnOnce<(&_,)>` is not implemented for `dyn std::ops::FnOnce(u32) -> bool`

Again, the error message is obvious.

nomad
  • 131
  • 1
  • 8
  • Also relevant: https://stackoverflow.com/q/42141129 You should be able to use the turbo fish notation to specify a concrete type for `F` in that call (`Box bool>` for example, the never type could be usef `!` in nightly), or even make a separate function to resolve the ambiguity. – E_net4 Jul 17 '20 at 16:21
  • almost. calling the fn as `sub_function::bool>(None)` can't be done either, since `FnOnce` is a trait. I would know a workaround by specifying a custom trait, that implements a `filter(...)` function, and have that trait directly implemented, passing it as type parameter to the function. Maybe it's not directly possible with closures? – nomad Jul 17 '20 at 16:24
  • ah looks like i'm tired. just saw your second answer. of course, I can store the closure on the heap. – nomad Jul 17 '20 at 16:25
  • In this case, you would not be storing anything in the heap, because it was called with `None`. This is just a way to resolve the ambiguity at type system level. Once you call it in a context which expects an actual function, then the type is already resolved. – E_net4 Jul 17 '20 at 16:29
  • yes. that's correct. – nomad Jul 17 '20 at 16:31

2 Answers2

1

You can use turbofish notation to specify the real type of None. Since this is in fact Option::<T>::None, i.e. is is generic itself, this is viable:

async fn main_call(&self) -> Result<()> {
    // Any type can be used here, since it won't be used anyway.
    let _list = self.sub_function(None::<fn(()) -> bool>).await;
    // do something with the result

    Ok(())
}

Here's a playground with your (slightly fixed to work as MCVE) example with this addition.

Cerberus
  • 8,879
  • 1
  • 25
  • 40
0

The None type must be explicitly known at compile time. So calling sub_function would look like this

async fn main_call(&self) -> Result<()> 
{
   let _list = self.sub_function::<u32, Box<dyn FnOnce(u32) -> bool>>(None).await;
   // do something with the result

   Ok(())
}
nomad
  • 131
  • 1
  • 8