為什麼是斐波那契數列
斐波那契數列十分適合用來實戰rust的迭代器,演算法也很簡單,一目瞭然。這個例子可以用來學習Iterator的使用,十分適合剛學習了rust的迭代器章節後用來練練手。
程式碼實戰
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>>());
}
分解知識點
- 程式碼定義了一個名字為Fib的元組結構體(tuple structs)。因為我們的實現封裝了實現細節,沒必要定義一個具名結構體。
網上有給出其他定義了名稱的結構體,個人覺得有點多餘了。比如這樣
struct Fibonacci {
a: u64,
b: u64,
}
- 第二點就是如何實現Iterator,關鍵就兩點,定義關聯型別和實現next方法
impl Iterator for Fib {
// 1. 定義關聯型別為usize
type Item = usize;
// 2. 實現next方法,這裡也是主要的邏輯
fn next(&mut self) -> Option<usize> {
*self = Fib(self.1, self.0 + self.1);
Some(self.0)
}
}
- 第三點是
*self = Fib(self.1, self.0 + self.1);
; self被定義為了可變引用(&mut), 這裡*self 解引用為Fib型別。
另外一種寫法
self = &mut Fib(self.1, self.0 + self.1);
上面定義了一個可變引用 &mut Fib 賦值給self,rust編譯器直接提示
|
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`
提示借用了臨時變數,臨時變數會被丟棄掉。其實就是&mut Fib 只是一個可變借用,在被借用給self後就會馬上失效了,self就會指向一個懸垂指標, rust編譯器肯定不會讓這種情況發生的(強行解釋一波,歡迎打臉)。
所以正確的做法是直接讓self獲取新建立的Fib的所有權就行了。也就是*self = Fib(self.1, self.0 + self.1);
。
- 第四點是
Fib::new().take(last).collect::<Vec<usize>>()
。 這裡直接在println巨集裡列印結果,編譯器推斷不出需要collect的型別,需要使用collect::標註。
除非是下面這種寫法,編譯器能自動推斷出來
let result: Vec<usize> = Fib::new().take(last).collect();
println!("fib({}) result: {:?}", last, result);
總結
本文通過rust iterator來實現斐波那契數列,需要掌握一下要點
- 元組結構體寫法
- 如何實現iterator trait
collect::<B>
幫助編譯器推斷型別