Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a closure from a function

Tags:

rust

Note: This question was asked before Rust's first stable release. There have been lots of changes since and the syntax used in the function is not even valid anymore. Still, Shepmaster's answer is excellent and makes this question worth keeping.


Finally unboxed closures have landed, so I am experimenting with them to see what you can do.

I have this simple function:

fn make_adder(a: int, b: int) -> || -> int {     || a + b } 

However, I get a missing lifetime specifier [E0106] error. I have tried to fix this by changing the return type to ||: 'static -> int, but then I get another error cannot infer an appropriate lifetime due to conflicting requirements.

If I understand correctly, the closure is unboxed so it owns a and b. It seems very strange to me that it needs a lifetime. How can I fix this?

like image 921
aochagavia Avatar asked Aug 22 '14 11:08

aochagavia


People also ask

Can you return from a closure?

Closures can also return values, and they are written similarly to parameters: you write them inside your closure, directly before the in keyword.

How do I return something to Swift closure?

Instead, in the closure, take the return value that you want in the cell and store it somewhere (in a member variable) and have the tableView update it itself (e.g. with tableView. reloadData() ). This will cause it to get the cell again (cellForRow ...).

How do you return a function in Rust?

The return keyword can be used to return a value inside a function's body. When this keyword isn't used, the last expression is implicitly considered to be the return value. If a function returns a value, its return type is specified in the signature using -> after the parentheses () .

What is function closure in JavaScript?

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function.


2 Answers

As of Rust 1.26, you can use impl trait:

fn make_adder(a: i32) -> impl Fn(i32) -> i32 {     move |b| a + b }  fn main() {     println!("{}", make_adder(1)(2)); } 

This allows returning an unboxed closure even though it is impossible to specify the exact type of the closure.

This will not help you if any of these are true:

  1. You are targeting Rust before this version

  2. You have any kind of conditional in your function:

    fn make_adder(a: i32) -> impl Fn(i32) -> i32 {     if a > 0 {         move |b| a + b     } else {         move |b| a - b     } } 

    Here, there isn't a single return type; each closure has a unique, un-namable type.

  3. You need to be able to name the returned type for any reason:

    struct Example<F>(F);  fn make_it() -> Example<impl Fn()> {     Example(|| println!("Hello")) }  fn main() {     let unnamed_type_ok = make_it();     let named_type_bad: /* No valid type here */ = make_it(); } 

    You cannot (yet) use impl SomeTrait as a variable type.

In these cases, you need to use indirection. The common solution is a trait object, as described in the other answer.

like image 59
Shepmaster Avatar answered Sep 28 '22 02:09

Shepmaster


It is possible to return closures inside Boxes, that is, as trait objects implementing certain trait:

fn make_adder(a: i32) -> Box<Fn(i32) -> i32> {     Box::new(move |b| a + b) }  fn main() {     println!("{}", make_adder(1)(2)); } 

(try it here)

There is also an RFC (its tracking issue) on adding unboxed abstract return types which would allow returning closures by value, without boxes, but this RFC was postponed. According to discussion in that RFC, it seems that some work is done on it recently, so it is possible that unboxed abstract return types will be available relatively soon.

like image 28
Vladimir Matveev Avatar answered Sep 28 '22 03:09

Vladimir Matveev