diff --git a/Closures.md b/Closures.md new file mode 100644 index 0000000..a209d68 --- /dev/null +++ b/Closures.md @@ -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` 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, +} + +impl Inventory { + fn giveaway(&self, user_preference: Option) -> 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` and call the `unwrap_or_else` method on `user_preference` + +The [`unwrap_or_else` method on `Option`](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`, in this case `ShirtColor`) + +If the `Option` is the `Some` variant `unwrap_or_else` returns the value form within the `Some`. + +If the `Option` 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 \ No newline at end of file diff --git a/Iteratos and Closures.md b/Iteratos and Closures.md new file mode 100644 index 0000000..e5dbce9 --- /dev/null +++ b/Iteratos and Closures.md @@ -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. \ No newline at end of file