Rust 标準庫中還提供了一系列被稱為 集合(collections)的資料結構,類似于JDK中
java.util
包下面的一些集合類(List/Set/Map等),這類集合指向的資料是存儲在堆上,意味着資料的數量不必在編譯期就已知,并且還能随着程式的運作增大或縮小,每種集合都有其适用的場景,在我們日常開發過程中是非常有用的。
1、Vector
1.1 作用
由标準庫提供,用來存儲多個相同類型的值,其值在記憶體中是連續存放的。
相關 api 介紹:https://doc.rust-lang.org/std/vec/struct.Vec.html
1.2 建立
①、Vec::new 函數
fn main() {
let v: Vec<i32> = Vec::new();
}
因為沒有向這個 vector 中插入任何值,Rust 并不知道我們想要儲存什麼類型的元素,是以無法進行類型推斷,這裡我們就增加了泛型
<i32>
,表示這個集合 v 隻能存放
i32
類型的資料。
②、vec![] 宏
fn main() {
let v = vec![1, 2, 3];
}
這裡我們提供了
i32
類型的初始值,Rust 可以推斷出
v
的類型是
Vec<i32>
,是以不需要加上泛型注解。
1.3 添加
fn main() {
let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);
}
通過 push() 向集合末尾添加元素,注意要聲明為
mut
使其可變。
1.4 修改
直接通過下标的方式修改:
fn main() {
let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);
v[0] = 3;
}
1.5 删除
①、通過下标删除
fn main() {
let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);
v.remove(0);
}
②、删除末尾元素
v.pop();
1.6 周遊
fn main() {
let mut v: Vec<i32> = vec![1,2,3,4];
// 周遊引用位址
for x in &v{
print!("{} ", x);
}
// 周遊下标
for x in 0..v.len(){
if let Some(num) = v.get(x) {
print!("{} ", num);
}
}
for x in v.iter() {
print!("{} ", x);
}
for x in v.into_iter() {
print!("{} ", x);
}
}
1.7 周遊修改
fn main() {
let mut v: Vec<i32> = vec![1,2,3,4];
for x in &mut v {
*x += 1;
}
println!("&mut v {:?}", v);
for x in v.iter_mut() {
*x += 1;
}
println!("v.iter_mut {:?}", v);
for x in 0..v.len() {
if let Some(num) = v.get_mut(x) {
*num += 1;
}
}
println!("0..v.len() get_mut {:?}", v);
let v1: Vec<i32> = v.iter().map(|x| x + 1).collect();
println!("v.iter().map().collect() {:?}", v1);
}
1.8 使用枚舉存儲不同類型
前面我們說vector 隻能儲存相同類型的值,但實際會有很多情況下我們要存儲不同類型的值,這時候就可以使用枚舉。
因為枚舉成員都被定義為相同的枚舉類型。
fn main() {
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
}
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
2、HashMap
2.1 作用
基于 hash 算法的存儲一組鍵值對 (key- value- pair) 的容器,可以通過 K(任意類型)來尋找資料,而不是通過索引。
2.2 建立
注意必須首先通過
use
引用标準庫中集合部分的
HashMap
。
HashMap
沒有被 prelude 自動引用。
标準庫中對
HashMap
的支援也相對較少,例如,并沒有内建的建構宏。
use std::collections::HashMap;
let mut map = HashMap::new();
PS:注意上面不指明 map 的類型,編譯是會報錯的。要麼指明編譯類型
let mut map: HashMap<String,i32> = HashMap::new()
;要麼通過類型推斷,像 map 中添加資料。
2.3 添加
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
}
像 vector 一樣,哈希 map 将它們的資料儲存在堆上,這個
HashMap
的鍵類型是
String
而值類型是
i32
。
類似于 vector,哈希 map 是同質的:所有的鍵必須是相同類型,值也必須都是相同類型。
2.4 修改
①、覆寫一個值
用相同的鍵插入一個不同的值,也就是連續調用兩次 insert ,其 key 相同,value 不同。
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 50);
println!("{:?}", scores);//{"Blue": 50}
}
②、key 不存在則插入,存在就不做操作
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores);//{"Blue": 10, "Yellow": 50}
}
Entry
的
or_insert
方法在鍵對應的值存在時就傳回這個值的可變引用,如果不存在則将參數作為新值插入并傳回新值的可變引用。
③、key 不存在則插入,存在做更新操作
fn main() {
use std::collections::HashMap;
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:?}", map);
}
列印結果:
{"world": 2, "hello": 1, "wonderful": 1}
由于
Entry
的
or_insert
方法在鍵對應的值存在時會傳回這個值的可變引用,我們通過
*
解引用然後去修改裡面的值。
2.5 删除
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"),50);
scores.remove(&String::from("Yellow"));
println!("{:?}", scores);//{"Blue": 10}
}
2.6 周遊
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"),50);
println!("{:?}", scores);//{"Blue": 10}
for (key, value) in &scores {
println!("{}: {}", key, value);
}
}