Advanced Functions and Closures in Rust
We can also pass functions to functions, like passing closures to functions.
This is useful when we want to pass a function we already defined instead of creating a new closure.
To pass in a function as an argument, we can use a function pointer specified using
fn is a type rather than a trait. So, we can use
If we recall from Closures section:
there are three closure traits:
Fn: specifies that the closure the variables in its environment immutably
FnMut: specifies the closure capture the variables in its environment mutably
FnOnce: specifies that the closure takes ownership of the values in its environment (thus cosuming the variables)
Function pointers implement all these three closure traits.
i.e., if we have a function that expects a closure, we can pass it a closure or function pointer. That's why it's preferable to write function that expects a closure instead of just pointer type.
In above code we can update
do_twice() function to take either closure or function like this:
Fn is closure trait bound whereas
fn which is a function pointer type.
The case in which we may only want to accept function pointer instead of functions pointers and closures is if you're interfacing with external code that does not support closures.
C functinos don't closures.
Another example where we can use closure or predefined function:
To pass in a function pointer to
map() method, we can do using fully qualified syntax:
Anoter useful pattern that exploits an implementation detail of tuple structs and tuple struct enum variants.
Tuple struct uses parantheses
() to initialize values inside the tuple struct which looks like function call.
Actually these initializers are implemented as functions that take in arguments and return an instance of that tuple struct.
That means we can use these initializers as function pointers:
Obviously closures can also be passed in.
Returning closures from functions.
This function returns a closure, but it's unfinished. Closures are represented using traits, so the function won't return a concrete type.
What we want to say is we want to return something that implements the
Fn trait taking in an integer and returning an integer.
The above syntax might not work in all situation. For example, like in this where we return a closue based on input argument:
So instead, we need to return a trait object, wrapped in smart pointer so compiler can know it's size like this: