diff --git a/en/src/SUMMARY.md b/en/src/SUMMARY.md index d0facbc..9921720 100644 --- a/en/src/SUMMARY.md +++ b/en/src/SUMMARY.md @@ -55,7 +55,7 @@ - [advanced](lifetime/advance.md) - [Functional programing](functional-programing/intro.md) - [Closure](functional-programing/cloure.md) - - [Iterator TODO](functional-programing/iterator.md) + - [Iterator](functional-programing/iterator.md) - [newtype and Sized TODO](newtype-sized.md) - [Smart pointers TODO](smart-pointers/intro.md) - [Box](smart-pointers/box.md) diff --git a/en/src/functional-programing/cloure.md b/en/src/functional-programing/cloure.md index 8df7250..7546057 100644 --- a/en/src/functional-programing/cloure.md +++ b/en/src/functional-programing/cloure.md @@ -186,7 +186,7 @@ fn exec<'a, F: __>(mut f: F) { } ``` -#### How does the compiler determine the trait +#### Which trait does the compiler prefer to use? - Fn: the closure uses the captured value by reference (&T) - FnMut: the closure uses the captured value by mutable reference (&mut T) - FnOnce: the closure uses the captured value by value (T) diff --git a/en/src/functional-programing/iterator.md b/en/src/functional-programing/iterator.md index 641413e..0a49c37 100644 --- a/en/src/functional-programing/iterator.md +++ b/en/src/functional-programing/iterator.md @@ -1,21 +1,329 @@ # Iterator +The iterator pattern allows us to perform some tasks on a sequence of items in turn. An iterator is responsible for the logic of iterating over each item and determining when the sequence has finished. -https://doc.rust-lang.org/stable/rust-by-example/flow_control/for.html#for-and-iterators +## for and iterator +```rust +fn main() { + let v = vec![1, 2, 3]; + for x in v { + println!("{}",x) + } +} +``` +In above code, You may consider `for` as a simple loop, but actually it is iterating over a iterator. + +By default `for` will apply the `into_iter` to the collection, and change it into a iterator. As a result, the following code is equivalent to previous one: +```rust +fn main() { + let v = vec![1, 2, 3]; + for x in v.into_iter() { + println!("{}",x) + } +} +``` + +1、🌟 ```rust,editable -// (all the type annotations are superfluous) -// A reference to a string allocated in read only memory -let pangram: &'static str = "the quick brown fox jumps over the lazy dog"; -println!("Pangram: {}", pangram); +/* Refactoring the following code using iterators */ +fn main() { + let arr = [0; 10]; + for i in 0..arr.len() { + println!("{}",arr[i]) + } +} +``` -// Iterate over words in reverse, no new string is allocated -println!("Words in reverse"); -for word in pangram.split_whitespace().rev() { - println!("> {}", word); +2、 🌟 One of the easiest ways to create an iterator is to use the range notion: `a..b`. +```rust,editble +/* Fill in the blank */ +fn main() { + let mut v = Vec::new(); + for n in __ { + v.push(n); + } + + assert_eq!(v.len(), 100); +} +``` + +## next method +All iterators implement a trait named `Iterator` that is defined in the standard library: +```rust +pub trait Iterator { + type Item; + + fn next(&mut self) -> Option; + + // methods with default implementations elided +} +``` + +And we can call the `next` method on iterators directly. + +3、🌟🌟 +```rust,editable +/* Fill the blanks and fix the errors. +Using two ways if possible */ +fn main() { + let v1 = vec![1, 2]; + + assert_eq!(v1.next(), __); + assert_eq!(v1.next(), __); + assert_eq!(v1.next(), __); +} +``` + +## into_iter, iter and iter_mut +In the previous section, we have mentioned that `for` will apply the `into_iter` to the collection, and change it into a iterator.However, this is not the only way to convert collections into iterators. + +`into_iter`, `iter`, `iter_mut`, all of them can convert an collection into iterator, but in different ways. + +- `into_iter` cosumes the collection, once the collection has been comsumed, it is no longer available for reuse, because its ownership has been moved within the loop. +- `iter`, this borrows each element of the collection through each iteration, thus leaving the collection untouched and available for reuse after the loop +- `iter_mut`, this mutably borrows each element of the collection, allowing for the collection to be modified in place. + +4、🌟 +```rust,editable +/* Make it work */ +fn main() { + let arr = vec![0; 10]; + for i in arr { + println!("{}", i) + } + + println!("{:?}",arr); +} +``` + +5、🌟 +```rust,editable +/* Fill in the blank */ +fn main() { + let mut names = vec!["Bob", "Frank", "Ferris"]; + + for name in names.__{ + *name = match name { + &mut "Ferris" => "There is a rustacean among us!", + _ => "Hello", + } + } + + println!("names: {:?}", names); +} +``` + +6、🌟🌟 +```rust,editable +/* Fill in the blank */ +fn main() { + let mut values = vec![1, 2, 3]; + let mut values_iter = values.__; + + if let Some(v) = values_iter.__{ + __ + } + + assert_eq!(values, vec![0, 2, 3]); +} +``` + + +## Creating our own iterator +We can not only create iterators from collections types, but also can create iterators by implementing the `Iterator` trait on our own types. + +**Example** +```rust +struct Counter { + count: u32, } -// Copy chars into a vector, sort and remove duplicates -let mut chars: Vec = pangram.chars().collect(); -chars.sort(); -chars.dedup(); +impl Counter { + fn new() -> Counter { + Counter { count: 0 } + } +} + +impl Iterator for Counter { + type Item = u32; + + fn next(&mut self) -> Option { + if self.count < 5 { + self.count += 1; + Some(self.count) + } else { + None + } + } +} + +fn main() { + let mut counter = Counter::new(); + + assert_eq!(counter.next(), Some(1)); + assert_eq!(counter.next(), Some(2)); + assert_eq!(counter.next(), Some(3)); + assert_eq!(counter.next(), Some(4)); + assert_eq!(counter.next(), Some(5)); + assert_eq!(counter.next(), None); +} +``` + +7、🌟🌟🌟 +```rust,editable +struct Fibonacci { + curr: u32, + next: u32, +} + +// Implement `Iterator` for `Fibonacci`. +// The `Iterator` trait only requires a method to be defined for the `next` element. +impl Iterator for Fibonacci { + // We can refer to this type using Self::Item + type Item = u32; + + /* Implement next method */ + fn next(&mut self) +} + +// Returns a Fibonacci sequence generator +fn fibonacci() -> Fibonacci { + Fibonacci { curr: 0, next: 1 } +} + +fn main() { + let mut fib = fibonacci(); + assert_eq!(fib.next(), Some(1)); + assert_eq!(fib.next(), Some(1)); + assert_eq!(fib.next(), Some(2)); + assert_eq!(fib.next(), Some(3)); + assert_eq!(fib.next(), Some(5)); +} +``` + +## Methods that Consume the Iterator +The `Iterator` trait has a number of methods with default implementations provided by the standard library. + + +### Consuming adaptors +Some of these methods call the method `next`to use up the iterator, so they are called *consuming adaptors*. + +8、🌟🌟 +```rust,edtiable +/* Fill in the blank and fix the errors */ +fn main() { + let v1 = vec![1, 2, 3]; + + let v1_iter = v1.iter(); + + // The sum method will take the ownership of the iterator and iterates through the items by repeatedly calling next method + let total = v1_iter.sum(); + + assert_eq!(total, __); + + println!("{:?}, {:?}",v1, v1_iter); +} +``` + + +#### collect +Other than converting a collection into an iterator, we can also `collect` the result values into a collection, `collect` will cosume the iterator. + +9、🌟🌟 +```rust,editable +/* Make it work */ +use std::collections::HashMap; +fn main() { + let names = [("sunface",18), ("sunfei",18)]; + let folks: HashMap<_, _> = names.into_iter().collect(); + + println!("{:?}",folks); + + let v1: Vec = vec![1, 2, 3]; + + let v2 = v1.iter().collect(); + + assert_eq!(v2, vec![1, 2, 3]); +} +``` + + +### Iterator adaptors +Methods allowing you to change one iterator into another iterator are known as *iterator adaptors*. You can chain multiple iterator adaptors to perform complex actions in a readable way. + +But beacuse **all iterators are lazy**, you have to call one of the consuming adapers to get results from calls to iterator adapters. + +10、🌟🌟 +```rust,editable +/* Fill in the blanks */ +fn main() { + let v1: Vec = vec![1, 2, 3]; + + let v2: Vec<_> = v1.iter().__.__; + + assert_eq!(v2, vec![2, 3, 4]); +} +``` + +11、🌟🌟 +```rust +/* Fill in the blanks */ +use std::collections::HashMap; +fn main() { + let names = ["sunface", "sunfei"]; + let ages = [18, 18]; + let folks: HashMap<_, _> = names.into_iter().__.collect(); + + println!("{:?}",folks); +} +``` + + +#### Using closures in iterator adaptors + +12、🌟🌟 +```rust +/* Fill in the blanks */ +#[derive(PartialEq, Debug)] +struct Shoe { + size: u32, + style: String, +} + +fn shoes_in_size(shoes: Vec, shoe_size: u32) -> Vec { + shoes.into_iter().__.collect() +} + +fn main() { + let shoes = vec![ + Shoe { + size: 10, + style: String::from("sneaker"), + }, + Shoe { + size: 13, + style: String::from("sandal"), + }, + Shoe { + size: 10, + style: String::from("boot"), + }, + ]; + + let in_my_size = shoes_in_size(shoes, 10); + + assert_eq!( + in_my_size, + vec![ + Shoe { + size: 10, + style: String::from("sneaker") + }, + Shoe { + size: 10, + style: String::from("boot") + }, + ] + ); +} ``` \ No newline at end of file diff --git a/solutions/functional-programing/iterator.md b/solutions/functional-programing/iterator.md new file mode 100644 index 0000000..f13dfb9 --- /dev/null +++ b/solutions/functional-programing/iterator.md @@ -0,0 +1,238 @@ +1、 +```rust +fn main() { + let arr = [0; 10]; + for i in arr { + println!("{}", i) + } +} +``` + +2、 +```rust +fn main() { + let mut v = Vec::new(); + for n in 1..101 { + v.push(n); + } + + assert_eq!(v.len(), 100); +} +``` + +3、 +```rust +fn main() { + let v1 = vec![1, 2]; + + // moving ownership + 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(), None); +} +``` + +```rust +fn main() { + let v1 = vec![1, 2]; + + // borrowing + let mut v1_iter = v1.iter(); + + assert_eq!(v1_iter.next(), Some(&1)); + assert_eq!(v1_iter.next(), Some(&2)); + assert_eq!(v1_iter.next(), None); +} +``` + +4、 +```rust +fn main() { + let arr = vec![0; 10]; + for i in arr.iter() { + println!("{}", i) + } + + println!("{:?}",arr); +} +``` + +5、 +```rust +fn main() { + let mut names = vec!["Bob", "Frank", "Ferris"]; + + for name in names.iter_mut() { + *name = match name { + &mut "Ferris" => "There is a rustacean among us!", + _ => "Hello", + } + } + + println!("names: {:?}", names); +} +``` + +6、 +```rust +fn main() { + let mut values = vec![1, 2, 3]; + let mut values_iter = values.iter_mut(); + + if let Some(v) = values_iter.next() { + *v = 0; + } + + assert_eq!(values, vec![0, 2, 3]); +} +``` + +7、 +```rust +struct Fibonacci { + curr: u32, + next: u32, +} + +// Implement `Iterator` for `Fibonacci`. +// The `Iterator` trait only requires a method to be defined for the `next` element. +impl Iterator for Fibonacci { + // We can refer to this type using Self::Item + type Item = u32; + + // Here, we define the sequence using `.curr` and `.next`. + // The return type is `Option`: + // * When the `Iterator` is finished, `None` is returned. + // * Otherwise, the next value is wrapped in `Some` and returned. + // We use Self::Item in the return type, so we can change + // the type without having to update the function signatures. + fn next(&mut self) -> Option { + let new_next = self.curr + self.next; + + self.curr = self.next; + self.next = new_next; + + // Since there's no endpoint to a Fibonacci sequence, the `Iterator` + // will never return `None`, and `Some` is always returned. + Some(self.curr) + } +} + +// Returns a Fibonacci sequence generator +fn fibonacci() -> Fibonacci { + Fibonacci { curr: 0, next: 1 } +} + +fn main() { + let mut fib = fibonacci(); + assert_eq!(fib.next(), Some(1)); + assert_eq!(fib.next(), Some(1)); + assert_eq!(fib.next(), Some(2)); + assert_eq!(fib.next(), Some(3)); + assert_eq!(fib.next(), Some(5)); +} +``` + +8、 +```rust +fn main() { + let v1 = vec![1, 2, 3]; + + let v1_iter = v1.iter(); + + // The sum method will take the ownership of the iterator and iterates through the items by repeatedly calling next method + let total: i32 = v1_iter.sum(); + + assert_eq!(total, 6); + + println!("{:?}",v1); +} +``` + +9、 +```rust +use std::collections::HashMap; +fn main() { + let names = [("sunface",18), ("sunfei",18)]; + let folks: HashMap<_, _> = names.into_iter().collect(); + + println!("{:?}",folks); + + let v1: Vec = vec![1, 2, 3]; + + let v2: Vec<_> = v1.into_iter().collect(); + + assert_eq!(v2, vec![1, 2, 3]); +} +``` + +10、 +```rust +fn main() { + let v1: Vec = vec![1, 2, 3]; + + let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); + + assert_eq!(v2, vec![2, 3, 4]); +} +``` + +11、 +```rust +use std::collections::HashMap; +fn main() { + let names = ["sunface", "sunfei"]; + let ages = [18, 18]; + let folks: HashMap<_, _> = names.into_iter().zip(ages.into_iter()).collect(); + + println!("{:?}",folks); +} +``` + +12、 +```rust +#[derive(PartialEq, Debug)] +struct Shoe { + size: u32, + style: String, +} + +fn shoes_in_size(shoes: Vec, shoe_size: u32) -> Vec { + shoes.into_iter().filter(|s| s.size == shoe_size).collect() +} + +fn main() { + let shoes = vec![ + Shoe { + size: 10, + style: String::from("sneaker"), + }, + Shoe { + size: 13, + style: String::from("sandal"), + }, + Shoe { + size: 10, + style: String::from("boot"), + }, + ]; + + let in_my_size = shoes_in_size(shoes, 10); + + assert_eq!( + in_my_size, + vec![ + Shoe { + size: 10, + style: String::from("sneaker") + }, + Shoe { + size: 10, + style: String::from("boot") + }, + ] + ); +} +``` \ No newline at end of file