From 127a97dc297b675047b871e9a72b8dd8ffe2ba8b Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 29 Mar 2022 14:59:12 +0800 Subject: [PATCH 01/22] Functional language features --- 13-functional-language-features/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 13-functional-language-features/README.md diff --git a/13-functional-language-features/README.md b/13-functional-language-features/README.md new file mode 100644 index 0000000..f719f39 --- /dev/null +++ b/13-functional-language-features/README.md @@ -0,0 +1 @@ +# 13. Functional language features: iterators and closures From 7cdedcf032d3548d2575af449feb977da684c766 Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 29 Mar 2022 15:04:50 +0800 Subject: [PATCH 02/22] --wip-- [skip ci] --- .../13-1-closures/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 13-functional-language-features/13-1-closures/README.md diff --git a/13-functional-language-features/13-1-closures/README.md b/13-functional-language-features/13-1-closures/README.md new file mode 100644 index 0000000..aa21b90 --- /dev/null +++ b/13-functional-language-features/13-1-closures/README.md @@ -0,0 +1,10 @@ +# 13.1. Closures: Anonymous functions that can capture their environment + +Closures: + +- can be saved in a variable +- can be passed as arguments to functions +- can be created in one place, and then later called to evaluate it in a different context +- can capture values from the scope in which they're defined (unlike functions) +- allow for code reuse +- allow for behavior customisation From 09629a4ae5150e8d079c422ec90dc3dc3954afd6 Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 29 Mar 2022 15:52:22 +0800 Subject: [PATCH 03/22] --wip-- [skip ci] --- .../workout_generator/Cargo.toml | 8 +++++ .../workout_generator/src/lib.rs | 1 + .../workout_generator/src/main.rs | 8 +++++ .../workout_generator/src/workout.rs | 29 +++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/Cargo.toml create mode 100644 13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/lib.rs create mode 100644 13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs create mode 100644 13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/Cargo.toml b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/Cargo.toml new file mode 100644 index 0000000..56f4002 --- /dev/null +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "workout_generator" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/lib.rs b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/lib.rs new file mode 100644 index 0000000..e3c76b4 --- /dev/null +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/lib.rs @@ -0,0 +1 @@ +pub mod workout; diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs new file mode 100644 index 0000000..97804d3 --- /dev/null +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs @@ -0,0 +1,8 @@ +use workout_generator::workout; + +fn main() { + let simulated_user_specified_value = 10; + let simulated_random_number = 7; + + workout::generate_workout(simulated_user_specified_value, simulated_random_number); +} diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs new file mode 100644 index 0000000..253d631 --- /dev/null +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs @@ -0,0 +1,29 @@ +use std::{thread, time::Duration}; + +fn simulated_expensive_calculation(intensity: u32) -> u32 { + println!("calculating slowly..."); + thread::sleep(Duration::from_secs(2)); // like timeout, timer + intensity +} + +pub fn generate_workout(intensity: u32, random_number: u32) { + if intensity < 25 { + println!( + "Today, do {} pushups!", + simulated_expensive_calculation(intensity) + ); + println!( + "Next, do {} situps!", + simulated_expensive_calculation(intensity) + ); + } else { + if random_number == 3 { + println!("Take a break today! Remeber to stay hydrated!"); + } else { + println!( + "Today, run for {} minutes", + simulated_expensive_calculation(intensity) + ); + } + } +} From 3bd1aa2d3b5f1ba9f114fd7599f11ff89adab599 Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 29 Mar 2022 15:52:43 +0800 Subject: [PATCH 04/22] --wip-- [skip ci] --- .../01-abstract-behavior/workout_generator/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs index 97804d3..f3a727f 100644 --- a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs @@ -2,7 +2,7 @@ use workout_generator::workout; fn main() { let simulated_user_specified_value = 10; - let simulated_random_number = 7; + let simulated_random_number = 3; workout::generate_workout(simulated_user_specified_value, simulated_random_number); } From 29e6bdb9ca6b5684dca767c1fa3845bfc5a24891 Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 29 Mar 2022 15:53:48 +0800 Subject: [PATCH 05/22] --wip-- [skip ci] --- .../01-abstract-behavior/workout_generator/src/main.rs | 2 +- .../01-abstract-behavior/workout_generator/src/workout.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs index f3a727f..97804d3 100644 --- a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/main.rs @@ -2,7 +2,7 @@ use workout_generator::workout; fn main() { let simulated_user_specified_value = 10; - let simulated_random_number = 3; + let simulated_random_number = 7; workout::generate_workout(simulated_user_specified_value, simulated_random_number); } diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs index 253d631..23d36e4 100644 --- a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs @@ -21,7 +21,7 @@ pub fn generate_workout(intensity: u32, random_number: u32) { println!("Take a break today! Remeber to stay hydrated!"); } else { println!( - "Today, run for {} minutes", + "Today, run for {} minutes!", simulated_expensive_calculation(intensity) ); } From 2970132046fe92bca9280a35a571d80aaabcd99c Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 29 Mar 2022 16:40:32 +0800 Subject: [PATCH 06/22] --wip-- [skip ci] --- .../workout_generator/src/workout.rs | 61 +++++++++++++++---- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs index 23d36e4..d121dbd 100644 --- a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs @@ -6,24 +6,61 @@ fn simulated_expensive_calculation(intensity: u32) -> u32 { intensity } +// Iteration #3: Define a closure, and store this definition in a variable so that it can be called later. +// This pattern seems similar to memoization - the first time `expensive_clousure` is called. +// the result is stored inside the variable itself. pub fn generate_workout(intensity: u32, random_number: u32) { + let expensive_closure = |num| simulated_expensive_calculation(num); + if intensity < 25 { - println!( - "Today, do {} pushups!", - simulated_expensive_calculation(intensity) - ); - println!( - "Next, do {} situps!", - simulated_expensive_calculation(intensity) - ); + println!("Today, do {} pushups!", expensive_closure(intensity)); + println!("Next, do {} situps!", expensive_closure(intensity)); } else { if random_number == 3 { println!("Take a break today! Remeber to stay hydrated!"); } else { - println!( - "Today, run for {} minutes!", - simulated_expensive_calculation(intensity) - ); + println!("Today, run for {} minutes!", expensive_closure(intensity)); } } } + +// Iteration #2 - refactor by storing the result of duplicated function calls in a variable. +// Still not ideal as expensive result gets run at least once, although it's not +// needed by the `random_number == 3` `if` block. +// pub fn generate_workout(intensity: u32, random_number: u32) { +// let expensive_result = simulated_expensive_calculation(intensity); + +// if intensity < 25 { +// println!("Today, do {} pushups!", expensive_result); +// println!("Next, do {} situps!", expensive_result); +// } else { +// if random_number == 3 { +// println!("Take a break today! Remeber to stay hydrated!"); +// } else { +// println!("Today, run for {} minutes!", expensive_result); +// } +// } +// } + +// Iteration #1 - expensive calculation called multiple times instead of once. +// pub fn generate_workout(intensity: u32, random_number: u32) { +// if intensity < 25 { +// println!( +// "Today, do {} pushups!", +// simulated_expensive_calculation(intensity) +// ); +// println!( +// "Next, do {} situps!", +// simulated_expensive_calculation(intensity) +// ); +// } else { +// if random_number == 3 { +// println!("Take a break today! Remeber to stay hydrated!"); +// } else { +// println!( +// "Today, run for {} minutes!", +// simulated_expensive_calculation(intensity) +// ); +// } +// } +// } From be3aecd80b8e8e9187e888d6fabd00d6a9e3f80c Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 29 Mar 2022 16:49:58 +0800 Subject: [PATCH 07/22] --wip-- [skip ci] --- .../01-abstract-behavior/workout_generator/src/workout.rs | 4 ++-- 13-functional-language-features/13-1-closures/README.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs index d121dbd..5a3f598 100644 --- a/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs +++ b/13-functional-language-features/13-1-closures/01-abstract-behavior/workout_generator/src/workout.rs @@ -7,8 +7,8 @@ fn simulated_expensive_calculation(intensity: u32) -> u32 { } // Iteration #3: Define a closure, and store this definition in a variable so that it can be called later. -// This pattern seems similar to memoization - the first time `expensive_clousure` is called. -// the result is stored inside the variable itself. +// This reintroduces the problem of the expensive calculation bein executed multiple times. +// The solution will be presented in the next crate in this series. pub fn generate_workout(intensity: u32, random_number: u32) { let expensive_closure = |num| simulated_expensive_calculation(num); diff --git a/13-functional-language-features/13-1-closures/README.md b/13-functional-language-features/13-1-closures/README.md index aa21b90..88dde1a 100644 --- a/13-functional-language-features/13-1-closures/README.md +++ b/13-functional-language-features/13-1-closures/README.md @@ -8,3 +8,4 @@ Closures: - can capture values from the scope in which they're defined (unlike functions) - allow for code reuse - allow for behavior customisation +- need to be called at least once for the compiler to infer the types of their parameters & return value, if no arguments from the outer scope are passed into the definition From 7e6dcd8b273afce592fbaac4fd4a59bec204d2c1 Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 29 Mar 2022 20:04:50 +0800 Subject: [PATCH 08/22] --wip-- [skip ci] --- .../workout_generator/Cargo.toml | 8 +++ .../workout_generator/src/cacher.rs | 0 .../workout_generator/src/lib.rs | 2 + .../workout_generator/src/main.rs | 8 +++ .../workout_generator/src/workout.rs | 66 +++++++++++++++++++ .../13-1-closures/README.md | 6 ++ 6 files changed, 90 insertions(+) create mode 100644 13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/Cargo.toml create mode 100644 13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs create mode 100644 13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/lib.rs create mode 100644 13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/main.rs create mode 100644 13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/workout.rs diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/Cargo.toml b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/Cargo.toml new file mode 100644 index 0000000..56f4002 --- /dev/null +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "workout_generator" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs new file mode 100644 index 0000000..e69de29 diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/lib.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/lib.rs new file mode 100644 index 0000000..f09b820 --- /dev/null +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/lib.rs @@ -0,0 +1,2 @@ +pub mod cacher; +pub mod workout; diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/main.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/main.rs new file mode 100644 index 0000000..97804d3 --- /dev/null +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/main.rs @@ -0,0 +1,8 @@ +use workout_generator::workout; + +fn main() { + let simulated_user_specified_value = 10; + let simulated_random_number = 7; + + workout::generate_workout(simulated_user_specified_value, simulated_random_number); +} diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/workout.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/workout.rs new file mode 100644 index 0000000..5a3f598 --- /dev/null +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/workout.rs @@ -0,0 +1,66 @@ +use std::{thread, time::Duration}; + +fn simulated_expensive_calculation(intensity: u32) -> u32 { + println!("calculating slowly..."); + thread::sleep(Duration::from_secs(2)); // like timeout, timer + intensity +} + +// Iteration #3: Define a closure, and store this definition in a variable so that it can be called later. +// This reintroduces the problem of the expensive calculation bein executed multiple times. +// The solution will be presented in the next crate in this series. +pub fn generate_workout(intensity: u32, random_number: u32) { + let expensive_closure = |num| simulated_expensive_calculation(num); + + if intensity < 25 { + println!("Today, do {} pushups!", expensive_closure(intensity)); + println!("Next, do {} situps!", expensive_closure(intensity)); + } else { + if random_number == 3 { + println!("Take a break today! Remeber to stay hydrated!"); + } else { + println!("Today, run for {} minutes!", expensive_closure(intensity)); + } + } +} + +// Iteration #2 - refactor by storing the result of duplicated function calls in a variable. +// Still not ideal as expensive result gets run at least once, although it's not +// needed by the `random_number == 3` `if` block. +// pub fn generate_workout(intensity: u32, random_number: u32) { +// let expensive_result = simulated_expensive_calculation(intensity); + +// if intensity < 25 { +// println!("Today, do {} pushups!", expensive_result); +// println!("Next, do {} situps!", expensive_result); +// } else { +// if random_number == 3 { +// println!("Take a break today! Remeber to stay hydrated!"); +// } else { +// println!("Today, run for {} minutes!", expensive_result); +// } +// } +// } + +// Iteration #1 - expensive calculation called multiple times instead of once. +// pub fn generate_workout(intensity: u32, random_number: u32) { +// if intensity < 25 { +// println!( +// "Today, do {} pushups!", +// simulated_expensive_calculation(intensity) +// ); +// println!( +// "Next, do {} situps!", +// simulated_expensive_calculation(intensity) +// ); +// } else { +// if random_number == 3 { +// println!("Take a break today! Remeber to stay hydrated!"); +// } else { +// println!( +// "Today, run for {} minutes!", +// simulated_expensive_calculation(intensity) +// ); +// } +// } +// } diff --git a/13-functional-language-features/13-1-closures/README.md b/13-functional-language-features/13-1-closures/README.md index 88dde1a..29519d0 100644 --- a/13-functional-language-features/13-1-closures/README.md +++ b/13-functional-language-features/13-1-closures/README.md @@ -9,3 +9,9 @@ Closures: - allow for code reuse - allow for behavior customisation - need to be called at least once for the compiler to infer the types of their parameters & return value, if no arguments from the outer scope are passed into the definition + +## Sample code + +[Naively call expensive function multiple times as needed](./01-abstract-behavior/workout_generator/src/workout.rs) + +[Lazy evaluation / lazily evaluate / memoization / memo / cache / caching implementation with a `Cacher` struct](./02-memoization-with-struct/workout_generator/src/) From 91647e6ce1d1d6cd4edbd52cdea3e8236bf72300 Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 5 Apr 2022 17:39:34 +0800 Subject: [PATCH 09/22] --wip-- [skip ci] --- 13-functional-language-features/13-1-closures/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/13-functional-language-features/13-1-closures/README.md b/13-functional-language-features/13-1-closures/README.md index 29519d0..e9f1b24 100644 --- a/13-functional-language-features/13-1-closures/README.md +++ b/13-functional-language-features/13-1-closures/README.md @@ -14,4 +14,4 @@ Closures: [Naively call expensive function multiple times as needed](./01-abstract-behavior/workout_generator/src/workout.rs) -[Lazy evaluation / lazily evaluate / memoization / memo / cache / caching implementation with a `Cacher` struct](./02-memoization-with-struct/workout_generator/src/) +[Lazy evaluation / lazily evaluate / memoization / memo / cache / caching implementation with a `Cacher` struct / `Fn` trait](./02-memoization-with-struct/workout_generator/src/) From 924b65ec01689a557d2871916ceb924f9580f8ad Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 5 Apr 2022 17:45:25 +0800 Subject: [PATCH 10/22] --wip-- [skip ci] --- .../workout_generator/src/cacher.rs | 8 ++++++++ 13-functional-language-features/13-1-closures/README.md | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs index e69de29..c970ed2 100644 --- a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs @@ -0,0 +1,8 @@ +pub struct Cacher +where + T: Fn(u32) -> u32, +{ + // trait bounds on `T` specify that `calculation` field is a closure by using the `Fn` trait + pub calculation: T, + pub value: Option, +} diff --git a/13-functional-language-features/13-1-closures/README.md b/13-functional-language-features/13-1-closures/README.md index e9f1b24..2084b91 100644 --- a/13-functional-language-features/13-1-closures/README.md +++ b/13-functional-language-features/13-1-closures/README.md @@ -14,4 +14,4 @@ Closures: [Naively call expensive function multiple times as needed](./01-abstract-behavior/workout_generator/src/workout.rs) -[Lazy evaluation / lazily evaluate / memoization / memo / cache / caching implementation with a `Cacher` struct / `Fn` trait](./02-memoization-with-struct/workout_generator/src/) +[Lazy evaluation / lazily evaluate / memoization / memo / cache / caching implementation with a `Cacher` struct typed with a `Fn` trait bound that closures must match](./02-memoization-with-struct/workout_generator/src/) From b345b5749a6fb73c403231c41e2d97a5235b569e Mon Sep 17 00:00:00 2001 From: David Chin Date: Sun, 10 Apr 2022 12:55:02 +0800 Subject: [PATCH 11/22] --wip-- [skip ci] --- .../workout_generator/src/cacher.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs index c970ed2..e5e158f 100644 --- a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs @@ -1,8 +1,14 @@ +// `Cacher` struct: +// - holds a closure in `calculation` field +// - `calculation` field is of the generic type `T` +// - trait bounds on `T` specify that it's a closure by using the `Fn` trait +// - closure stored on `calculation` field must have on `u32` parameter and +// must return a `u32` +// - holds an optional result in `value` field pub struct Cacher where T: Fn(u32) -> u32, { - // trait bounds on `T` specify that `calculation` field is a closure by using the `Fn` trait pub calculation: T, pub value: Option, } From 56b53bd30edff0be87e45e0b0e58936c66bc1635 Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 19 Apr 2022 15:11:31 +0800 Subject: [PATCH 12/22] --wip-- [skip ci] --- .../workout_generator/src/cacher.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs index e5e158f..6513372 100644 --- a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs @@ -1,14 +1,21 @@ // `Cacher` struct: // - holds a closure in `calculation` field -// - `calculation` field is of the generic type `T` -// - trait bounds on `T` specify that it's a closure by using the `Fn` trait -// - closure stored on `calculation` field must have on `u32` parameter and -// must return a `u32` -// - holds an optional result in `value` field +// - holds an optional result, `Option`, in the `value` field pub struct Cacher where T: Fn(u32) -> u32, { + // - `calculation` field is of the generic type `T` + // - trait bounds on `T` specify that it's a closure by using the `Fn` trait + // - closure stored on `calculation` field must have on `u32` parameter and + // must return a `u32` pub calculation: T, + + // - before the closure is executed, `value` will be `None` + // - when code using a `Cacher` askd for the result of the closure, the `Cacher` + // will execute the closure and store the result within a `Some` variant in the + // `value` field + // - if the code asks for the result of the clousure again, instead of executing the + // closure again, the `Cacher` will return the result held in the `Some` variant pub value: Option, } From 2544414784398f9862f65f56a773ad7db4457f52 Mon Sep 17 00:00:00 2001 From: David Chin Date: Tue, 19 Apr 2022 15:30:05 +0800 Subject: [PATCH 13/22] --wip-- [skip ci] --- .../workout_generator/src/cacher.rs | 30 ++++++++- .../workout_generator/src/main.rs | 12 ++++ .../workout_generator/src/workout.rs | 67 ++++--------------- 3 files changed, 53 insertions(+), 56 deletions(-) diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs index 6513372..63cfa33 100644 --- a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/cacher.rs @@ -9,13 +9,39 @@ where // - trait bounds on `T` specify that it's a closure by using the `Fn` trait // - closure stored on `calculation` field must have on `u32` parameter and // must return a `u32` - pub calculation: T, + calculation: T, + // The following logic is defined in `impl Cacher`: // - before the closure is executed, `value` will be `None` // - when code using a `Cacher` askd for the result of the closure, the `Cacher` // will execute the closure and store the result within a `Some` variant in the // `value` field // - if the code asks for the result of the clousure again, instead of executing the // closure again, the `Cacher` will return the result held in the `Some` variant - pub value: Option, + value: Option, +} + +impl Cacher +where + T: Fn(u32) -> u32, +{ + // takes a generic parameter `T`, which is defined as having the same trait bound + // as the `Cacher` struct + pub fn new(calculation: T) -> Cacher { + Cacher { + calculation, + value: None, + } + } + + pub fn value(&mut self, arg: u32) -> u32 { + match self.value { + Some(v) => v, + None => { + let v = (self.calculation)(arg); + self.value = Some(v); + v + } + } + } } diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/main.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/main.rs index 97804d3..f077a05 100644 --- a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/main.rs +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/main.rs @@ -1,8 +1,20 @@ use workout_generator::workout; fn main() { + // calculating slowly... + // Today, do 10 pushups! + // Next, do 10 situps! let simulated_user_specified_value = 10; let simulated_random_number = 7; + // calculating slowly... + // Today, run for 100 minutes! + // let simulated_user_specified_value = 100; + // let simulated_random_number = 7; + + // Take a break today! Remeber to stay hydrated! + // let simulated_user_specified_value = 100; + // let simulated_random_number = 3; + workout::generate_workout(simulated_user_specified_value, simulated_random_number); } diff --git a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/workout.rs b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/workout.rs index 5a3f598..56bd51a 100644 --- a/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/workout.rs +++ b/13-functional-language-features/13-1-closures/02-memoization-with-struct/workout_generator/src/workout.rs @@ -1,66 +1,25 @@ +use crate::cacher::Cacher; use std::{thread, time::Duration}; -fn simulated_expensive_calculation(intensity: u32) -> u32 { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); // like timeout, timer - intensity -} - -// Iteration #3: Define a closure, and store this definition in a variable so that it can be called later. -// This reintroduces the problem of the expensive calculation bein executed multiple times. -// The solution will be presented in the next crate in this series. +// Iteration #: Using `Cacher` struct pub fn generate_workout(intensity: u32, random_number: u32) { - let expensive_closure = |num| simulated_expensive_calculation(num); + let mut expensive_result = Cacher::new(|num| { + println!("calculating slowly..."); + thread::sleep(Duration::from_secs(2)); + num + }); if intensity < 25 { - println!("Today, do {} pushups!", expensive_closure(intensity)); - println!("Next, do {} situps!", expensive_closure(intensity)); + println!("Today, do {} pushups!", expensive_result.value(intensity)); + println!("Next, do {} situps!", expensive_result.value(intensity)); } else { if random_number == 3 { println!("Take a break today! Remeber to stay hydrated!"); } else { - println!("Today, run for {} minutes!", expensive_closure(intensity)); + println!( + "Today, run for {} minutes!", + expensive_result.value(intensity) + ); } } } - -// Iteration #2 - refactor by storing the result of duplicated function calls in a variable. -// Still not ideal as expensive result gets run at least once, although it's not -// needed by the `random_number == 3` `if` block. -// pub fn generate_workout(intensity: u32, random_number: u32) { -// let expensive_result = simulated_expensive_calculation(intensity); - -// if intensity < 25 { -// println!("Today, do {} pushups!", expensive_result); -// println!("Next, do {} situps!", expensive_result); -// } else { -// if random_number == 3 { -// println!("Take a break today! Remeber to stay hydrated!"); -// } else { -// println!("Today, run for {} minutes!", expensive_result); -// } -// } -// } - -// Iteration #1 - expensive calculation called multiple times instead of once. -// pub fn generate_workout(intensity: u32, random_number: u32) { -// if intensity < 25 { -// println!( -// "Today, do {} pushups!", -// simulated_expensive_calculation(intensity) -// ); -// println!( -// "Next, do {} situps!", -// simulated_expensive_calculation(intensity) -// ); -// } else { -// if random_number == 3 { -// println!("Take a break today! Remeber to stay hydrated!"); -// } else { -// println!( -// "Today, run for {} minutes!", -// simulated_expensive_calculation(intensity) -// ); -// } -// } -// } From c42d31dd19272911e669fd1a6b0e45c274e9ac1d Mon Sep 17 00:00:00 2001 From: David Chin Date: Wed, 20 Apr 2022 07:38:58 +0800 Subject: [PATCH 14/22] --wip-- [skip ci] --- 13-functional-language-features/13-1-closures/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/13-functional-language-features/13-1-closures/README.md b/13-functional-language-features/13-1-closures/README.md index 2084b91..28154e1 100644 --- a/13-functional-language-features/13-1-closures/README.md +++ b/13-functional-language-features/13-1-closures/README.md @@ -15,3 +15,5 @@ Closures: [Naively call expensive function multiple times as needed](./01-abstract-behavior/workout_generator/src/workout.rs) [Lazy evaluation / lazily evaluate / memoization / memo / cache / caching implementation with a `Cacher` struct typed with a `Fn` trait bound that closures must match](./02-memoization-with-struct/workout_generator/src/) + +[Capturing the environment with Closures](TODO) From 1a22adf4c15262cc930e67925071eda173b3d9e8 Mon Sep 17 00:00:00 2001 From: David Chin Date: Wed, 20 Apr 2022 07:54:57 +0800 Subject: [PATCH 15/22] --wip-- [skip ci] --- .../13-2-iterators/README.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 13-functional-language-features/13-2-iterators/README.md diff --git a/13-functional-language-features/13-2-iterators/README.md b/13-functional-language-features/13-2-iterators/README.md new file mode 100644 index 0000000..a57fbf1 --- /dev/null +++ b/13-functional-language-features/13-2-iterators/README.md @@ -0,0 +1,26 @@ +# Processing a series of items with iterators + +- iterator pattern is code that performs some task on a sequence of items in turn +- an iterator is responsible for: + - the logic of iterating over each item + - determining when a sequence is finished +- an iterator is lazy: + - it has no effect until... + - ...the code calls methods that consume the iterator to use it up + +```rust +let v1 = vec![1, 2, 3]; // vector `v1` + +// - call `iter` method defined on `Vec` +// -> creates iterator `v1_iter` over items in vector `v1` +// - at this point, the code does not do anything useful; +// - remember that an iterator is lazy +let v1_iter = v1.iter(); + +// use `v1_iter` with a `for` loop to run code on each item on every iteration +for val in v1_iter { + println!("Got: {}", val); +} +``` + +## The `Iterator` trait and the `next` method From 2902fbba3af144bf3c1033b0ea6a69f24933d8e9 Mon Sep 17 00:00:00 2001 From: David Chin Date: Wed, 20 Apr 2022 08:02:08 +0800 Subject: [PATCH 16/22] --wip-- [skip ci] --- .../13-2-iterators/README.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/13-functional-language-features/13-2-iterators/README.md b/13-functional-language-features/13-2-iterators/README.md index a57fbf1..3218476 100644 --- a/13-functional-language-features/13-2-iterators/README.md +++ b/13-functional-language-features/13-2-iterators/README.md @@ -24,3 +24,23 @@ for val in v1_iter { ``` ## The `Iterator` trait and the `next` method + +Iterators implement a trait named `Iterator` that is defined in the standard library: + +```rust +pub trait Iterator { + // new syntax (A): `type Item` + type Item; + + // new syntax (A): `Self::Item` + fn next(&mut self) -> Option; + + // methods with default implementations elided +} +``` + +`new syntax (A)` defines an associated type with this trait: + +- implementing the `Iterator` trait requires an `Item` type to be defined +- the `Item` type is used in the return type of the `next` method +- the `Item` type will be the type returned from the iterator From 491672dd08cbcabeec91c98bef420eb1a928ee27 Mon Sep 17 00:00:00 2001 From: David Chin Date: Wed, 20 Apr 2022 08:06:26 +0800 Subject: [PATCH 17/22] --wip-- [skip ci] --- 13-functional-language-features/13-2-iterators/README.md | 2 +- 19-advanced-features/19-2-advanced-traits/README.md | 7 +++++++ 19-advanced-features/README.md | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 19-advanced-features/19-2-advanced-traits/README.md create mode 100644 19-advanced-features/README.md diff --git a/13-functional-language-features/13-2-iterators/README.md b/13-functional-language-features/13-2-iterators/README.md index 3218476..4103fc6 100644 --- a/13-functional-language-features/13-2-iterators/README.md +++ b/13-functional-language-features/13-2-iterators/README.md @@ -39,7 +39,7 @@ pub trait Iterator { } ``` -`new syntax (A)` defines an associated type with this trait: +`new syntax (A)` defines an [associated type](../../19-advanced-features/19-2-advanced-traits/README.md/#specifying-placeholder-types-in-trait-definitions-with-associated-types) with this trait: - implementing the `Iterator` trait requires an `Item` type to be defined - the `Item` type is used in the return type of the `next` method diff --git a/19-advanced-features/19-2-advanced-traits/README.md b/19-advanced-features/19-2-advanced-traits/README.md new file mode 100644 index 0000000..9085a1a --- /dev/null +++ b/19-advanced-features/19-2-advanced-traits/README.md @@ -0,0 +1,7 @@ +# Advanced traits + +## Specifying placeholder types in trait definitions with associated types + +Referenced by: + +[The `Iterator` trait and the `next` method](../../13-functional-language-features/13-2-iterators/README.md/#the-iterator-trait-and-the-next-method) diff --git a/19-advanced-features/README.md b/19-advanced-features/README.md new file mode 100644 index 0000000..7c935bd --- /dev/null +++ b/19-advanced-features/README.md @@ -0,0 +1 @@ +# Advanced features From 2f84844759ff3f1af360eba31ede689dff80582d Mon Sep 17 00:00:00 2001 From: David Chin Date: Wed, 20 Apr 2022 08:07:08 +0800 Subject: [PATCH 18/22] --wip-- [skip ci] --- 19-advanced-features/19-2-advanced-traits/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/19-advanced-features/19-2-advanced-traits/README.md b/19-advanced-features/19-2-advanced-traits/README.md index 9085a1a..1cee064 100644 --- a/19-advanced-features/19-2-advanced-traits/README.md +++ b/19-advanced-features/19-2-advanced-traits/README.md @@ -4,4 +4,4 @@ Referenced by: -[The `Iterator` trait and the `next` method](../../13-functional-language-features/13-2-iterators/README.md/#the-iterator-trait-and-the-next-method) +- [The `Iterator` trait and the `next` method](../../13-functional-language-features/13-2-iterators/README.md/#the-iterator-trait-and-the-next-method) From a63903ae7cf098b7d751c11bfdc4207f38f7c5de Mon Sep 17 00:00:00 2001 From: David Chin Date: Thu, 21 Apr 2022 17:41:40 +0800 Subject: [PATCH 19/22] --wip-- [skip ci] --- .../13-2-iterators/README.md | 44 +++++++++++++++++++ .../13-2-iterators/iterators/Cargo.toml | 8 ++++ .../13-2-iterators/iterators/src/main.rs | 9 ++++ 3 files changed, 61 insertions(+) create mode 100644 13-functional-language-features/13-2-iterators/iterators/Cargo.toml create mode 100644 13-functional-language-features/13-2-iterators/iterators/src/main.rs diff --git a/13-functional-language-features/13-2-iterators/README.md b/13-functional-language-features/13-2-iterators/README.md index 4103fc6..353f8d4 100644 --- a/13-functional-language-features/13-2-iterators/README.md +++ b/13-functional-language-features/13-2-iterators/README.md @@ -44,3 +44,47 @@ pub trait Iterator { - implementing the `Iterator` trait requires an `Item` type to be defined - the `Item` type is used in the return type of the `next` method - the `Item` type will be the type returned from the iterator + +Implementors of the `Iterator` trait must define one method, the `next` method: + +- which returns one item of the iterator at a time wrapped in `Some`, +- and, when the iteration is over, returns `None` + +The `next` method can be called on iterators directly: + +```rust +#[test] +fn iterator_demonstration() { + let v1 = vec![1, 2, 3]; + + // Note (A) + // v1_iter must be mutable, otherwise error on `v1_iter.next()`: + // cannot borrow `v1_iter` as mutable, as it is not declared as mutable + let mut v1_iter = v1.iter(); + + // Note (B) + // `Some(&1)`, otherwise error: + // expected `&{integer}`, found integer + assert_eq!(v1_iter.next(), Some(&1)); + assert_eq!(v1_iter.next(), Some(&2)); + assert_eq!(v1_iter.next(), Some(&3)); + assert_eq!(v1_iter.next(), None); +} +``` + +Note (A): Iterator `v1_iter` needs to be made mutable: + +- calling the `next` method changes the internal state used by the iterator: + - the internal state is used to keep track of where the iterator is in the sequence +- calling `next`: + - consumes, or uses up, the iterator + - eats up an iterm from the iterator +- `v1_iter` needn't be made mutable when used in a `for` loop because: + - the loop takes ownership of `v1_iter` and makes it mutable behind the scenes + +Note (B): Values obtained from calls to `next`: + +- are immutable references to the values in the vector `v1` +- the `iter` method in `v1.iter()` produces an iterator over immutable references: + - to create an iterator that takes ownership of `v1` and returns owned values, use `into_iter` + - to create an iterator over mutable references, use `iter_mut` diff --git a/13-functional-language-features/13-2-iterators/iterators/Cargo.toml b/13-functional-language-features/13-2-iterators/iterators/Cargo.toml new file mode 100644 index 0000000..069541a --- /dev/null +++ b/13-functional-language-features/13-2-iterators/iterators/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "iterators" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/13-functional-language-features/13-2-iterators/iterators/src/main.rs b/13-functional-language-features/13-2-iterators/iterators/src/main.rs new file mode 100644 index 0000000..35bd387 --- /dev/null +++ b/13-functional-language-features/13-2-iterators/iterators/src/main.rs @@ -0,0 +1,9 @@ +fn main() { + let v = vec![1, 2, 3]; + let mut v_iter = v.iter(); + assert_eq!(v_iter.next(), Some(&1)); + assert_eq!(v_iter.next(), Some(&2)); + assert_eq!(v_iter.next(), Some(&3)); + assert_eq!(v_iter.next(), None); + println!("{:?}", v_iter.next()); +} From 1f19bcd5d19738a6116ae8d8c609455e63d6b2b7 Mon Sep 17 00:00:00 2001 From: David Chin Date: Thu, 21 Apr 2022 17:52:14 +0800 Subject: [PATCH 20/22] --wip-- [skip ci] --- .../13-2-iterators/README.md | 26 +++++++++++++++---- .../13-2-iterators/iterators/src/main.rs | 15 ++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/13-functional-language-features/13-2-iterators/README.md b/13-functional-language-features/13-2-iterators/README.md index 353f8d4..8c37547 100644 --- a/13-functional-language-features/13-2-iterators/README.md +++ b/13-functional-language-features/13-2-iterators/README.md @@ -39,7 +39,7 @@ pub trait Iterator { } ``` -`new syntax (A)` defines an [associated type](../../19-advanced-features/19-2-advanced-traits/README.md/#specifying-placeholder-types-in-trait-definitions-with-associated-types) with this trait: +**`new syntax (A)`** defines an [associated type](../../19-advanced-features/19-2-advanced-traits/README.md/#specifying-placeholder-types-in-trait-definitions-with-associated-types) with this trait: - implementing the `Iterator` trait requires an `Item` type to be defined - the `Item` type is used in the return type of the `next` method @@ -69,10 +69,26 @@ fn iterator_demonstration() { assert_eq!(v1_iter.next(), Some(&2)); assert_eq!(v1_iter.next(), Some(&3)); assert_eq!(v1_iter.next(), None); + + // Note (C) `into_iter` + let v1 = vec![1, 2, 3]; + let mut v1_iter = v1.into_iter(); + assert_eq!(v1_iter.next(), Some(1)); + assert_eq!(v1_iter.next(), Some(2)); + assert_eq!(v1_iter.next(), Some(3)); + assert_eq!(v1_iter.next(), None); + + // Note (D) `iter_mut` + let mut v1 = vec![1, 2, 3]; + let mut v1_iter = v1.iter_mut(); + assert_eq!(v1_iter.next(), Some(&mut 1)); + assert_eq!(v1_iter.next(), Some(&mut 2)); + assert_eq!(v1_iter.next(), Some(&mut 3)); + assert_eq!(v1_iter.next(), None); } ``` -Note (A): Iterator `v1_iter` needs to be made mutable: +**Note (A)**: Iterator `v1_iter` needs to be made mutable: - calling the `next` method changes the internal state used by the iterator: - the internal state is used to keep track of where the iterator is in the sequence @@ -82,9 +98,9 @@ Note (A): Iterator `v1_iter` needs to be made mutable: - `v1_iter` needn't be made mutable when used in a `for` loop because: - the loop takes ownership of `v1_iter` and makes it mutable behind the scenes -Note (B): Values obtained from calls to `next`: +**Note (B)**: Values obtained from calls to `next`: - are immutable references to the values in the vector `v1` - the `iter` method in `v1.iter()` produces an iterator over immutable references: - - to create an iterator that takes ownership of `v1` and returns owned values, use `into_iter` - - to create an iterator over mutable references, use `iter_mut` + - **Note (C)**: to create an iterator that takes ownership of `v1` and returns owned values, use `into_iter` + - **Note (D)**: to create an iterator over mutable references, use `iter_mut` diff --git a/13-functional-language-features/13-2-iterators/iterators/src/main.rs b/13-functional-language-features/13-2-iterators/iterators/src/main.rs index 35bd387..4018584 100644 --- a/13-functional-language-features/13-2-iterators/iterators/src/main.rs +++ b/13-functional-language-features/13-2-iterators/iterators/src/main.rs @@ -5,5 +5,18 @@ fn main() { assert_eq!(v_iter.next(), Some(&2)); assert_eq!(v_iter.next(), Some(&3)); assert_eq!(v_iter.next(), None); - println!("{:?}", v_iter.next()); + + let v = vec![1, 2, 3]; + let mut v_iter = v.into_iter(); + assert_eq!(v_iter.next(), Some(1)); + assert_eq!(v_iter.next(), Some(2)); + assert_eq!(v_iter.next(), Some(3)); + assert_eq!(v_iter.next(), None); + + let mut v = vec![1, 2, 3]; + let mut v_iter = v.iter_mut(); + assert_eq!(v_iter.next(), Some(&mut 1)); + assert_eq!(v_iter.next(), Some(&mut 2)); + assert_eq!(v_iter.next(), Some(&mut 3)); + assert_eq!(v_iter.next(), None); } From 0d72169f1fa2e697fe212f25492c5417eb079b3d Mon Sep 17 00:00:00 2001 From: David Chin Date: Thu, 21 Apr 2022 17:56:48 +0800 Subject: [PATCH 21/22] --wip-- [skip ci] --- 13-functional-language-features/13-2-iterators/README.md | 6 +++++- .../13-2-iterators/iterators/src/main.rs | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/13-functional-language-features/13-2-iterators/README.md b/13-functional-language-features/13-2-iterators/README.md index 8c37547..163a2b2 100644 --- a/13-functional-language-features/13-2-iterators/README.md +++ b/13-functional-language-features/13-2-iterators/README.md @@ -70,9 +70,13 @@ fn iterator_demonstration() { assert_eq!(v1_iter.next(), Some(&3)); assert_eq!(v1_iter.next(), None); - // Note (C) `into_iter` + // Note (C) `into_iter` takes ownership of v1 let v1 = vec![1, 2, 3]; let mut v1_iter = v1.into_iter(); + // Error (E1) ----------- `v1` moved due to this method call + // println!("{:?}", v1); // Error (E1) will occur + // Error (E1) ^^ value borrowed here after move + assert_eq!(v1_iter.next(), Some(1)); assert_eq!(v1_iter.next(), Some(2)); assert_eq!(v1_iter.next(), Some(3)); diff --git a/13-functional-language-features/13-2-iterators/iterators/src/main.rs b/13-functional-language-features/13-2-iterators/iterators/src/main.rs index 4018584..b46182b 100644 --- a/13-functional-language-features/13-2-iterators/iterators/src/main.rs +++ b/13-functional-language-features/13-2-iterators/iterators/src/main.rs @@ -6,8 +6,9 @@ fn main() { assert_eq!(v_iter.next(), Some(&3)); assert_eq!(v_iter.next(), None); - let v = vec![1, 2, 3]; - let mut v_iter = v.into_iter(); + let v1 = vec![1, 2, 3]; + let mut v_iter = v1.into_iter(); + println!("{:?}", v1); assert_eq!(v_iter.next(), Some(1)); assert_eq!(v_iter.next(), Some(2)); assert_eq!(v_iter.next(), Some(3)); From f9f2d5f223fc0ca4cb23f324051388eddd0b9574 Mon Sep 17 00:00:00 2001 From: David Chin Date: Sat, 23 Apr 2022 13:29:25 +0800 Subject: [PATCH 22/22] --wip-- [skip ci] --- 13-functional-language-features/13-2-iterators/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/13-functional-language-features/13-2-iterators/README.md b/13-functional-language-features/13-2-iterators/README.md index 163a2b2..802f546 100644 --- a/13-functional-language-features/13-2-iterators/README.md +++ b/13-functional-language-features/13-2-iterators/README.md @@ -106,5 +106,5 @@ fn iterator_demonstration() { - are immutable references to the values in the vector `v1` - the `iter` method in `v1.iter()` produces an iterator over immutable references: - - **Note (C)**: to create an iterator that takes ownership of `v1` and returns owned values, use `into_iter` - - **Note (D)**: to create an iterator over mutable references, use `iter_mut` + - **Note (C)**: `into_iter` - creates an iterator that takes ownership of `v1` and returns owned values + - **Note (D)**: `iter_mut` - creates an iterator over mutable references