Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a closure as an argument of another closure?

The code is as follows:

fn main() {
  let arg = | | println!("closure");
  let call_twice = | c | { c(); c(); };
  call_twice(arg);
}

But the compiler can't inference the correct type of the argument c. Error message:

error: the type of this value must be known in this context

How can I tell the compiler that the type of the argument is a generic type which impls Fn?


Edit: If the argument type is trait object, the code can be accepted by compiler. But the indirection isn't necessary, is it?

fn main() {
  let arg = | | println!("closure");
  let call_twice = | c :&Fn() | { c(); c(); };
  call_twice(&arg);
}

Thanks for your answer. But it is the type inference problem that confuse me. Using an fn can make the compiler happy.

fn main() {
 let arg = | | println!("closure");

 // now compiler knows the argument `c` is a closure
 fn call_twice<F>(c: F) where F:Fn() {c(); c();}

 call_twice(arg);
}

Can we add a syntax to support similar functionality? Such as for<F> | c:F | where F:Fn() {c(); c();}.

like image 594
F001 Avatar asked Oct 18 '22 18:10

F001


1 Answers

Following the guidelines in the Rust book section on returning closures to turn the closure into a move closure and boxing it, this is what I had to do to get your program to run at the Rust Playground:

fn main() {
    let arg = Box::new(move || println!("closure"));
    let call_twice = |c: Box<Fn()>| { c(); c(); };
    call_twice(arg);
}

Edit to address OP's most recent edit: No. The issue you're dealing with is ultimately not a type inference problem. If it was just type inference, then all we would have had to was tell the closure that c was a closure. The actual problem is that "Closure parameters must be local variables and all local variables must have sizes that are known at compile-time." Rust function parameters, on the other hand, apparently don't have this requirement.

like image 84
Judah Meek Avatar answered Oct 21 '22 22:10

Judah Meek