向量
就像我們有 &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>
}