Functional Programming in Rust 1: Closures
Table of Contents

What is Functional Programming? #
It is a Programming Paradigm where you use functions to solve what you are building. The most common features that you might have used FP in any language will be Map and Reduce. Where you pass in a function what iterates in the collection you run map or reduce on.
Rust has some functional features too that I plan to write here.
Closures #
Let’s do a quick Google search “closures”; The first result that comes to me is from MDN.
Let’s see what MDN has to say(even though it is JS).
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.
What information can we take from this statement? #
- It is a function that is inside a function
- The inner function shares the same environment as the outer function.
What information we can conclude from this statement? #
- The variables defined in the outer function are accessible in the inner function.
There is a lot of information that is left here in the context of rust, but hold on for a while :D
Syntax for closure in Rust. #
Take a look carefully at how you can create closures in rust.
- You give no type signatures for the formal arguments.
| |
- You give no return type signatures for the closure.
| |
- You give types for the formal arguments and the return signatures.
| |
So closures in rust are kind of “Pythonic” in a way where you can choose to give function type signatures, Right? Yes, but to an extent. Look at this example
Playing with Closures !!!! #
| |
You might expect this program to compile correctly and on runtime to print 21 and 21.
But we received a compile error.
Output
| |
When we dissect the error(Rust has the best errors btw) we see that on the second time the compiler says that “expected usize found u8” and then gives a suggestion.
So we learn that closure takes the first arguments type and return type as the type signature of the closure.
Playing with closures(again) #
| |
Output
| |
We can observe here that variable b is accessible inside of closure a, so we can conclude that a closure shares the same scope as the parent.
Phew, a lot of stuff to learn. Let’s break down what I wrote down #
- Closures are functions that are inside a function and hence share the same scope as the parent function.
- They are “Pythonic” in a way that they do not need type signatures but instead the compiler gives it a signature based on the type of arguments on the first call.
Moving values inside closures. #
If you’re reading this blog I expect you to know what a move in rust is. If you don’t you can read this.
So there are three ways of moving values into closues.
- Immutable immutable
- Mutable argument
- Borrowing
Example of Immutable arguments #
| |
Output
| |
Example of Mutable arguments #
| |
Output
| |
Example of borrowing #
| |
Output
| |
Moving captured values out of fn traits #
So, once a value or a reference has been passed to the closure, The closure decides what happens with it. It could use the value once and drop it, mutate the value or can take references to a value and do all of these.
Why do we have to do this? Since Rust has this philosophy of all errors being compiled time errors and not runtime errors, we need to know how the values are being handled inside the closure so that in the runtime we do not get any UBs.
This defines three types of closures traits when they are passed in functions or structs.
FnOnce-> Uses the value which is passed in it and drops itFnMut-> It can modify the passed valuesFn-> Can take any reference
Example of FnOnce #
Consider the rust option enum. Rust option enum has a unwrap_or_else function that returns Some value or runs the closure to provide the value for.
Let’s dissect the code below.
| |
Observations #
- The function returns a type
Twhich is the value held by the option enum - There is a trait bound
fwhich isFnOnceand returns the same type as the enum.
So we see can conclude that we need to pass in a closure that takes in no arguments to unwrap_or_else and return the same value as the option and it has to run only once.
Example of FnMut #
| |
| |
Example of Fn #
| |
Output
| |