started ch13.1 with files
All checks were successful
Test Gitea Actions / first (push) Successful in 13s

This commit is contained in:
darkicewolf50 2025-02-19 23:51:24 +00:00
parent 1ba56701cf
commit f2e65b3550
2 changed files with 148 additions and 0 deletions

128
Closures.md Normal file
View File

@ -0,0 +1,128 @@
# Closures: Anonymous Functions that Capture Their Environment
Rust closures are anonymous functions you can save in a variable or pass as an argument ot other functions
You create the closure in one plcae and then call the closure elsewhere to evaluate it in a different context.
Unlike functions, closures can capture values form the scope in which they are defined
This will be demonstrated how thee closure features allow for code reuse and behavior customization
## Capturing the Environment with Closures
We will first examine how we can use closures to capture values fomr the environment they are defined in for later use
Here is the scenario that we will use to examine this:
Every so often, our t-shirt company gives away an exclusive, limited-edition shirt to someone on our mailing list as a promotion.
People on the mailing list can optionally add their colour to their profile.
If the persion cohsen for a free shirt has their favourite colour set, they get that colour shirt.
If the persion hasn't specified a favourite colour, they get whatever colour the company currently gas the most of.
There are many ways to implement this.
For example we are going to use an enum called `ShirtColor` that has the varaiants `Red` and `Blue`(we limit the number of colours avaialable for simplicity)
We represent the company's inventory with an `Inventory` struct that has a field named `shirts` that contains a `Vec<ShirtColor>` reperenting the shirt colours currently in stock.
The method `giveaway` defined on `Inventory` gets the optional shirt colour preference of the free shirt winner, and reutnrs the shirt colour the person will get.
Here is the setup
```rust
#[derive(Debug, PartialEq, Copy, Clone)]
enum ShirtColor {
Red,
Blue,
}
struct Inventory {
shirts: Vec<ShirtColor>,
}
impl Inventory {
fn giveaway(&self, user_preference: Option<ShirtColor>) -> ShirtColor {
user_preference.unwrap_or_else(|| self.most_stocked())
}
fn most_stocked(&self) -> ShirtColor {
let mut num_red = 0;
let mut num_blue = 0;
for color in &self.shirts {
match color {
ShirtColor::Red => num_red += 1,
ShirtColor::Blue => num_blue += 1,
}
}
if num_red > num_blue {
ShirtColor::Red
} else {
ShirtColor::Blue
}
}
}
fn main() {
let store = Inventory {
shirts: vec![ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue],
};
let user_pref1 = Some(ShirtColor::Red);
let giveaway1 = store.giveaway(user_pref1);
println!(
"The user with preference {:?} gets {:?}",
user_pref1, giveaway1
);
let user_pref2 = None;
let giveaway2 = store.giveaway(user_pref2);
println!(
"The user with preference {:?} gets {:?}",
user_pref2, giveaway2
);
}
```
The `store` defined in `main` has two blue shirts and one red shirt remaining to distribute for this limited-edition promotion
We call the `giveaway` method for a user with a preference for a red shirt and a user without any preference.
Once again this code could b implemented in man ways and here, to focus on closures, we are stuck to concepts you already learned except for the body of the `giveaway` method that uses a closure.
In the `giveaway` method, we get the user preference as a paramter of type `Option<ShirtColor>` and call the `unwrap_or_else` method on `user_preference`
The [`unwrap_or_else` method on `Option<T>`](https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap_or_else) is defined by the std library.
It takes one argument: a closure without any args that returns a value `T` (the same tpe stored in the `Some` variant of the `Option<T>`, in this case `ShirtColor`)
If the `Option<T>` is the `Some` variant `unwrap_or_else` returns the value form within the `Some`.
If the `Option<T>` is the `None` varaint, `unwrap_or_else` calls the closure and returns the value returned by the cloosure.
We specify the closure expression `|| self.most_stocked()` as the argument to `unwrap_or_else`.
This is a closure that takes no paramters itself (if the closure has paramters, they would appear between the two verticalbars).
The body of thee closure calls `self.most_stocked()`
We are defining the closure here and the implementation of `unwrap_or_else` will evaluate the closure later if the result is needed
Here is the output of this code
```
$ cargo run
Compiling shirt-company v0.1.0 (file:///projects/shirt-company)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.27s
Running `target/debug/shirt-company`
The user with preference Some(Red) gets Red
The user with preference None gets Blue
```
One aspect to notice is here is that we have passed a closure that calls `self.most_stocked()` on current `Inventory` intance.
The std library didn't need to know anything about te `Inventory` or `ShirtColor` types we defined or the logic we want to use in this scenario.
The closure captures an immutalbe reference to the `self` `Inventory` instance and passes ot woth the code we specify to the `unwrap_or_else` method
Funcions on the other hand are not able to capture their environment in this way.
## Closure Type Inference and Annoation

20
Iteratos and Closures.md Normal file
View File

@ -0,0 +1,20 @@
# Functional Language Features: Iterators and Closures
Rust's design has taken inspiration from many exisitng languages and techniques
One significant influence is *functional programming*
Programming in a functional style often include using functions as values by passing them in args, returning them form other unfcitons, assigning them to varaibles for later execution and so forth.
This chapter/section won't debate the issue of what functional programming is or isn't.
It will discuss some features of Rust that are similar to features in many languages often referred to as functional
It will cover:
- [*Closures*](./Closures.md) - a function-like construct you can store in a variable
- *Iterators* - a way of processing a series of elements
- How to use colsure and iterators to improve the I/O project (minigrep)
- The preformance of closures and iterators (Spoiler alert: they are faster than you might think!)
We have already covered some other Rust freatures, such as pattern matchin and enums, that are also influenced by the functional style.
Mastering closures and iterators is an improtant part of wiritng idiomatic, fast Rust code.