Performant Software Systems with Rust — Lecture 10
What Is Functional Programming?
Closures
First Example
Every so often, our t-shirt company gives away an exclusive, limited-edition shirt as a promotion
People can optionally add their favorite color to their profile
If the person chosen for a free shirt has their favorite color set, they get that color shirt
Otherwise, they get whatever color the company currently has the most of
Closure Type Inference and Annotation
Closures don’t usually require you to annotate the types of the parameters or the return value
fn functions doBut we can add type annotations too, if needed
Learn more: Closure Type Inference and Annotation
Closures with Type Annotation
Learn more: Closure Type Inference and Annotation
Closures with Type Annotation and Inference
What happens if we compile this code?
Three Ways of Capturing Values From the Environment
Borrowing immutably
Borrowing mutably
Taking ownership
Let’s look at an example on each
Learn more: Capturing References or Moving Ownership
Borrowing Immutably
Learn more: Capturing References or Moving Ownership
Borrowing Mutably
Learn more: Capturing References or Moving Ownership
Taking Ownership
Learn more: Capturing References or Moving Ownership
How is unwrap_or_else() in Option<T> defined?
Fn Traits
FnOnce: closures that can be called once
FnMut: closures that don’t move captured values out of their body, but may mutate the captured values
Fn: closures that don’t move captured values out of their body, and don’t mutate captured values, or capture nothing
Using the sort_by_key method with closures
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let mut list = [
Rectangle { width: 10, height: 1 },
Rectangle { width: 3, height: 5 },
Rectangle { width: 7, height: 12 },
];
// closure may be called multiple times
// so it takes an `FnMut` closure
list.sort_by_key(|r| r.width);
println!("{list:#?}");
}Will this work?
No, since it moves value out of the closure by transferring ownership of value to sort_operations, and can only be called once — an FnOnce closure.
Will this work?
Yes, since it only captures a mutable reference to num_sort_operations — an FnMut closure.
Iterators
Learn more: Processing a Series of Items with Iterators
Using an iterator in a for loop
The Iterator Trait and the next Method
Learn more: The Iterator Trait and the next Method
iter() vs. into_iter() vs. iter_mut()
With iter(), next() returns immutable references to values in the vector
To create an iterator that takes ownership, call into_iter()
To iterate over mutable references, call iter_mut()
Methods that Consume the Iterator
Methods, such as sum(), that call next() are called consuming adaptors, because calling them uses up the iterator
Learn more: Methods that Consume the Iterator
Methods that Produce Other Iterators
Iterator adaptors don’t consume the iterator
Instead, they produce different iterators by changing some aspect of the original iterator
Learn more: Methods that Produce Other Iterators
Calling the iterator adaptor map() to create a new iterator
We need to consume the iterator — they are lazy — and the closure never gets called!
Learn more: Methods that Produce Other Iterators
Learn more: Methods that Produce Other Iterators
Using Closures that Capture Their Environment
Learn more: Using Closures that Capture Their Environment
The Rust Programming Language, Chapter 13.1, 13.2