Returning a closure

As threads within Rust use a return from a closure, it makes sense for us to consider that it is entirely possible to return a closure. However, returning a closure is not as straightforward as you'd expect.

Let's consider a normal function first:

fn add_five(x : i32) -> i32  
{ 
    return x + 5; 
} 
fn main() 
{ 
    let test = add_five(5); 
    println!("{}", test); 
} 

This will output the value 10. It's not rocket science. Let's change this to a closure:

fn add_five_closure() ->(Fn(i32)->i32) 
{ 
    let num = 5; 
    |x| x + num 
} 
fn main() 
{ 
    let test = add_five_closure(); 
    let f = test(5); 
    println!("{}", f); 
} 
The code for the example can be found in Chapter 11/return_closure_one.

When we run this, though, we don't get the expected answer of 10—instead we get this:

Figure 9

So what has gone wrong? When we return from a function, we have to tell the compiler the type we're returning. However, Fn is a trait, so we have to somehow satisfy this requirement. We could always have it return a reference:

fn add_five_closure() -> &(Fn(i32)->i32) 

This will generate another compiler error as it needs a lifetime expectancy applied.

We could always make the function return a lifetime static reference:

fn add_five_closure() -> &'static (Fn(i32) → i32) 

However, this will produce a different error, which may look somewhat confusing:

Figure 10

Why are the types mismatched? It's expecting an i32, but has found a closure. Makes sense really, but why is this happening?

This is down to how Rust works. For a closure, it generates its own struct and implementation of Fn (and anything else required) therefore, we're dealing not with a literal, but something else.

Trying to return a trait object (such as Box) won't work either as the function relies on the num binding (which is stack allocated). However, if we move from the stack to the heap, we can now return the closure:

fn add_five_closure() -> Box<(Fn(i32) ->→ i32)> 
{ 
    let num = 5; 
    Box::new(move |x| x + num) 
} 
fn main() 
{ 
    let test = add_five_closure(); 
    let f = test(5); 
    println!("{}", f); 
} 
The source for this can be found in Chapter 11/return_closure_three.

This will now compile and give the following:

Figure 11
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset