Why Fibonacci Sequence
The Fibonacci sequence is well suited for the iterator used in real-world rust, and the algorithm is simple and straightforward. This example can be used to learn the use of Iterator and is a good example for practice after learning the iterator chapter of rust.
Code Actual
don't bb, show me the code
struct Fib(usize, usize); impl Fib { fn new() -> Fib { Fib(0, 1) } } impl Iterator for Fib { type Item = usize; fn next(&mut self) -> Option<usize> { *self = Fib(self.1, self.0 + self.1); Some(self.0) } } fn main() { let last = 20; println!("fib({}) result: {:?}", last, Fib::new().take(last).collect::<Vec<usize>>()); }
Decomposition Knowledge Points
- The code defines a tuple structs named Fib. Since our implementation encapsulates implementation details, it is not necessary to define a named structure.
There are other structures on the web that give names, which I find redundant. Like this
struct Fibonacci { a: u64, b: u64, }
- The second is how to implement Iterator. The key is to define the type of association and implement the next method
impl Iterator for Fib { // 1. Define the association type as usize type Item = usize; // 2. Implement the next method, which is also the main logic here fn next(&mut self) -> Option<usize> { *self = Fib(self.1, self.0 + self.1); Some(self.0) } }
- The third point is *self = Fib (self.1, self.0 + self.1). Self is defined as a variable reference (&mut), where *self dereferences are of type Fib.
Another way of writing
self = &mut Fib(self.1, self.0 + self.1);
The above defines a mut Fib assignment to self, prompted directly by the rust compiler
| 12 | self = &mut Fib(self.1, self.0 + self.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign to immutable argument error[E0716]: temporary value dropped while borrowed --> src\main.rs:12:21 | 11 | fn next(&mut self) -> Option<usize> { | - let's call the lifetime of this reference `'1` 12 | self = &mut Fib(self.1, self.0 + self.1); | ------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | | | | creates a temporary which is freed while still in use | assignment requires that borrow lasts for `'1`
The prompt borrows a temporary variable and the temporary variable is discarded. In fact, &mut Fib is just a variable borrowing and will expire immediately after being lent to self, which points to a dangling pointer, which the rust compiler will not allow (force a wave, welcome a face).
So the right thing to do is just let self take ownership of the newly created Fib. That is *self = Fib(self.1, self.0 + self.1);.
- The fourth point is Fib:: new (). Take(last). Collect:: <Vec<usize>(). The results are printed directly here in the println macro, and the compiler cannot infer the type that needs to be collected. Instead, use the collect:: label.
The compiler can infer this automatically unless it is written in the following way
let result: Vec<usize> = Fib::new().take(last).collect(); println!("fib({}) result: {:?}", last, result);
summary
In order to implement Fibonacci series by rust iterator, we need to master some key points.
- Tuple Structural Writing
- How to implement iterator trait
- collect:: Helps the compiler infer types
Why Fibonacci Sequence
The Fibonacci sequence is well suited for the iterator used in real-world rust, and the algorithm is simple and straightforward. This example can be used to learn the use of Iterator and is a good example for practice after learning the iterator chapter of rust.
Code Actual
don't bb, show me the code
struct Fib(usize, usize); impl Fib { fn new() -> Fib { Fib(0, 1) } } impl Iterator for Fib { type Item = usize; fn next(&mut self) -> Option<usize> { *self = Fib(self.1, self.0 + self.1); Some(self.0) } } fn main() { let last = 20; println!("fib({}) result: {:?}", last, Fib::new().take(last).collect::<Vec<usize>>()); }
Decomposition Knowledge Points
- The code defines a tuple structs named Fib. Since our implementation encapsulates implementation details, it is not necessary to define a named structure.
There are other structures on the web that give names, which I find redundant. Like this
struct Fibonacci { a: u64, b: u64, }
- The second is how to implement Iterator. The key is to define the type of association and implement the next method
impl Iterator for Fib { // 1. Define the association type as usize type Item = usize; // 2. Implement the next method, which is also the main logic here fn next(&mut self) -> Option<usize> { *self = Fib(self.1, self.0 + self.1); Some(self.0) } }
- The third point is *self = Fib (self.1, self.0 + self.1). Self is defined as a variable reference (&mut), where *self dereferences are of type Fib.
Another way of writing
self = &mut Fib(self.1, self.0 + self.1);
The above defines a mut Fib assignment to self, prompted directly by the rust compiler
| 12 | self = &mut Fib(self.1, self.0 + self.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign to immutable argument error[E0716]: temporary value dropped while borrowed --> src\main.rs:12:21 | 11 | fn next(&mut self) -> Option<usize> { | - let's call the lifetime of this reference `'1` 12 | self = &mut Fib(self.1, self.0 + self.1); | ------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | | | | creates a temporary which is freed while still in use | assignment requires that borrow lasts for `'1`
The prompt borrows a temporary variable and the temporary variable is discarded. In fact, &mut Fib is just a variable borrowing and will expire immediately after being lent to self, which points to a dangling pointer, which the rust compiler will not allow (force a wave, welcome a face).
So the right thing to do is just let self take ownership of the newly created Fib. That is *self = Fib(self.1, self.0 + self.1);.
- The fourth point is Fib:: new (). Take(last). Collect:: <Vec<usize>(). The results are printed directly here in the println macro, and the compiler cannot infer the type that needs to be collected. Instead, use the collect:: label.
The compiler can infer this automatically unless it is written in the following way
let result: Vec<usize> = Fib::new().take(last).collect(); println!("fib({}) result: {:?}", last, result);
summary
In order to implement Fibonacci series by rust iterator, we need to master some key points.
- Tuple Structural Writing
- How to implement iterator trait
- Collect:: <B>Helps the compiler infer types