向量
就像我們有 &str
和 String
一樣的方式,我們有陣列和向量(vector)。陣列的功能少了就快,向量的功能多了就慢。(當然,Rust 的速度一直都是非常快的,所以向量並不慢,只是比陣列慢一點)。型別被寫作 Vec
,你也可以直接叫它 "vec"。
向量的宣告主要有兩種方式。一種像 String
使用 new
:
fn main() { let name1 = String::from("Windy"); let name2 = String::from("Gomesy"); let mut my_vec = Vec::new(); // 如果我們現在就跑程式,編譯器會給出錯誤。 // 它不知道vec的型別。 my_vec.push(name1); // 現在它知道了:它是Vec<String> my_vec.push(name2); }
你可以看到 Vec
裡面總是有其他東西,這就是 <>
(角括號)的作用。Vec<String>
是有一或多個 String
的向量。你還可以在裡面有更多的型別。舉例來說:
Vec<(i32, i32)>
這個Vec
的每個元素是元組(tuple):(i32, i32)
。Vec<Vec<String>>
這個Vec
裡面有包含String
的Vec
。假設說你想把你喜歡的書保存在Vec<String>
。然後你再拿另一本書重做一次,就會得到另一個Vec<String>
。為了保留這兩本書,你會把它們放入另一個Vec
中,這就是Vec<Vec<String>>
。
與其使用 .push()
讓 Rust 決定型別,不如直接宣告型別。
fn main() { let mut my_vec: Vec<String> = Vec::new(); // 編譯器知道型別 // 所以沒有錯誤。 }
你可以看到,向量中的元素必須具有相同的型別。
建立向量的另一個簡單方法是使用 vec!
巨集。它看起來像一個陣列宣告,但前面有 vec!
。
fn main() { let mut my_vec = vec![8, 10, 10]; }
型別是 Vec<i32>
。你稱它為 "i32 的 Vec"。而 Vec<String>
是 "String 的 Vec"。Vec<Vec<String>>
是 "String 的 Vec 的 Vec"。
你也可以對一個向量進行切片,就像用在陣列一樣。
fn main() { let vec_of_ten = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // 所有東西都和前面的陣列一樣,除了我們加上vec!。 let three_to_five = &vec_of_ten[2..5]; let start_at_two = &vec_of_ten[1..]; let end_at_five = &vec_of_ten[..5]; let everything = &vec_of_ten[..]; println!("Three to five: {:?}, start at two: {:?} end at five: {:?} everything: {:?}", three_to_five, start_at_two, end_at_five, everything); }
因為向量比陣列慢,我們可以用一些方法讓它更快。向量都有容量(capacity),也就是給予向量使用的空間。當你在向量上推送一個新元素時,它會越來越接近容量。然後,如果你超過了容量,它將使其容量翻倍,並將元素複製到新的空間。這就是所謂的再分配(reallocation)。我們將使用名為 .capacity()
的方法,在我們向它新增元素時來查看向量的容量。
例如:
fn main() { let mut num_vec = Vec::new(); println!("{}", num_vec.capacity()); // 0 個元素: 印出 0 num_vec.push('a'); // 加人一個字元 println!("{}", num_vec.capacity()); // 1 個元素: 印出 4. 一筆資料的 Vec 容量永遠從 4 開始 num_vec.push('a'); // 多加一個 num_vec.push('a'); // 多加一個 num_vec.push('a'); // 多加一個 println!("{}", num_vec.capacity()); // 4 個元素: 仍印出 4. num_vec.push('a'); // 多加一個 println!("{}", num_vec.capacity()); // 印出 8. 我們有 5 個元素, 但容量從 4 加倍到 8 騰出了空間 }
印出:
0
4
4
8
所以這個向量再分配兩次:0 到 4,4 到 8。我們可以讓它更快:
fn main() { let mut num_vec = Vec::with_capacity(8); // 給它容量 8 num_vec.push('a'); // 加一個字元 println!("{}", num_vec.capacity()); // 印出 8 num_vec.push('a'); // 再加一個 println!("{}", num_vec.capacity()); // 印出 8 num_vec.push('a'); // 再加一個 println!("{}", num_vec.capacity()); // 印出 8. num_vec.push('a'); // 再加一個 num_vec.push('a'); // 再加一個 // 現在我們有 5 個元素 println!("{}", num_vec.capacity()); // 仍是 8 }
這個向量比較好再分配是 0 次。所以如果你認為你知道你需要多少元素,你可以使用 Vec::with_capacity()
來使它更快。
你記得你可以用 .into()
把 &str
變成 String
。你也可以用它把一個陣列變成 Vec
。你必須告訴 .into()
你想要 Vec
,但你可以不用選擇 Vec
的型別。如果你不想選擇,你可以寫 Vec<_>
。
fn main() { let my_vec: Vec<u8> = [1, 2, 3].into(); let my_vec2: Vec<_> = [9, 0, 10].into(); // Vec<_> 表示 "幫我選 Vec 的型別" // Rust 會選 Vec<i32> }