迄今為止,我們前面遇到的數(shù)據(jù)類型基本都是棧上存儲的。Rust 標(biāo)準(zhǔn)庫中包含一系列被稱為 集合(collections)的非常有用的數(shù)據(jù)結(jié)構(gòu)。這些集合指向的數(shù)據(jù)是儲存在堆上的,這意味著數(shù)據(jù)的數(shù)量不必在編譯時(shí)就已知,并且還可以隨著程序的運(yùn)行增長或縮小。本篇我們將了解三個(gè)在 Rust 程序中被廣泛使用的集合:
- vector 允許我們一個(gè)挨著一個(gè)地儲存一系列數(shù)量可變的值
-
字符串(string)是字符的集合。我們之前見過
String
類型,不過在本章我們將深入了解。 - 哈希 map(hash map)允許我們將值與一個(gè)特定的鍵(key)相關(guān)聯(lián)。這是一個(gè)叫做 map 的更通用的數(shù)據(jù)結(jié)構(gòu)的特定實(shí)現(xiàn)。
vector
我們要講到的第一個(gè)類型是 Vec<T>
,也被稱為 vector。vector 允許我們在一個(gè)單獨(dú)的數(shù)據(jù)結(jié)構(gòu)中儲存多于一個(gè)的值,它在內(nèi)存中彼此相鄰地排列所有的值。vector 只能儲存相同類型的值。
vector的創(chuàng)建
新建一個(gè)空的vector:
let v: Vec<i32> = Vec::new();
為了方便 Rust 提供了 vec!
宏,這個(gè)宏會根據(jù)我們提供的字面值來創(chuàng)建一個(gè)新的 vector。
let v = vec![1, 2, 3];
增加元素
向vector增加元素:
fn main() {
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
}
訪問元素
通過索引或使用 get
方法讀取vector里的元素:
fn main() {
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {third}");
let third: Option<&i32> = v.get(2);
match third {
Some(third) => println!("The third element is {third}"),
None => println!("There is no third element."),
}
}
兩者區(qū)別是使用不合法的索引值會讓索引方式的代碼發(fā)生panic,而get方法因?yàn)槭欠祷匾粋€(gè)Option<&T>,所以只是返回一個(gè)None。
遍歷元素
使用for in遍歷vector:
fn main() {
let v = vec![100, 32, 57];
for i in &v {
println!("{i}");
}
}
或者在遍歷可變vector時(shí)進(jìn)行修改:
fn main() {
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
}
使用枚舉存儲不同類型的數(shù)據(jù)
由于vector只能存儲同類型的數(shù)據(jù),對于不同類型的數(shù)據(jù),可以將它們跟枚舉值進(jìn)行關(guān)聯(lián),這樣vector就能存儲這些枚舉值。
元素的生命周期
丟棄vector的時(shí)候,也會丟棄其中的元素。
string
很多 Vec
可用的操作在 String
中同樣可用,事實(shí)上 String
被實(shí)現(xiàn)為一個(gè)帶有一些額外保證、限制和功能的字節(jié) vector 的封裝。
創(chuàng)建字符串
新建一個(gè)空字符串:
let mut s = String::new();
使用 to_string
方法從任何實(shí)現(xiàn)了 Display
trait 的類型,比如字符串字面值,創(chuàng)建字符串:
fn main() {
let data = "initial contents";
let s = data.to_string();
// 該方法也可直接用于字符串字面值:
let s = "initial contents".to_string();
}
從字符串字面值創(chuàng)建:
let s = String::from("initial contents");
字符串或者字符的附加
可以通過 push_str
方法來附加字符串 slice,從而使 String
變長:
fn main() {
let mut s = String::from("foo");
s.push_str("bar");
}
通過push
方法來附加一個(gè)單獨(dú)的字符到string后面:
fn main() {
let mut s = String::from("lo");
s.push('l');
}
使用+來拼接字符串,需要注意這里使用的是引用:
fn main() {
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = s1 + "-" + &s2 + "-" + &s3;
}
使用 format!
宏格式化拼接字符串:
fn main() {
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{s1}-{s2}-{s3}");
}
不支持索引
Rust 的字符串不支持索引。使用下標(biāo)索引字符串可能發(fā)生錯(cuò)誤。
創(chuàng)建字符串slice
索引字符串通常是一個(gè)壞點(diǎn)子,因?yàn)樽址饕龖?yīng)該返回的類型是不明確的:字節(jié)值、字符、字形簇或者字符串 slice。因此,如果你真的希望使用索引創(chuàng)建字符串 slice 時(shí),Rust 會要求你更明確一些。為了更明確索引并表明你需要一個(gè)字符串 slice,相比使用 []
和單個(gè)值的索引,可以使用 []
和一個(gè) range 來創(chuàng)建含特定字節(jié)的字符串 slice:
#![allow(unused)]
fn main() {
let hello = "Здравствуйте";
let s = &hello[0..4];
}
里,s
會是一個(gè) &str
,它包含字符串的頭四個(gè)字節(jié)。早些時(shí)候,我們提到了這些字母都是兩個(gè)字節(jié)長的,所以這意味著 s
將會是 “Зд”。而當(dāng)你訪問到了非字符邊界,你就會得到一個(gè)panic。
遍歷字符串
使用 chars
方法遍歷字符串的每個(gè)char:
#![allow(unused)]
fn main() {
for c in "Зд".chars() {
println!("{c}");
}
}
bytes
方法返回每一個(gè)原始字節(jié):
#![allow(unused)]
fn main() {
for b in "Зд".bytes() {
println!("");
}
}
HashMap
HashMap<K, V>
類型儲存了一個(gè)鍵類型 K
對應(yīng)一個(gè)值類型 V
的映射。它通過一個(gè) 哈希函數(shù)(hashing function)來實(shí)現(xiàn)映射,決定如何將鍵和值放入內(nèi)存中。很多編程語言支持這種數(shù)據(jù)結(jié)構(gòu),不過通常有不同的名字:哈希、map、對象、哈希表或者關(guān)聯(lián)數(shù)組。
創(chuàng)建HashMap
可以使用 new
創(chuàng)建一個(gè)空的 HashMap
,并使用 insert
增加元素:
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
}
訪問值
可以通過 get
方法并提供對應(yīng)的鍵來從哈希 map 中獲取值:
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let team_name = String::from("Blue");
let score = scores.get(&team_name).copied().unwrap_or(0);
}
get
方法返回 Option<&V>
,如果某個(gè)鍵在哈希 map 中沒有對應(yīng)的值,get
會返回 None
。程序中通過調(diào)用 copied
方法來獲取一個(gè) Option<i32>
而不是 Option<&i32>
,接著調(diào)用 unwrap_or
在 score
中沒有該鍵所對應(yīng)的項(xiàng)時(shí)將其設(shè)置為零。
遍歷HashMap
可以使用與 vector 類似的方式來遍歷哈希 map 中的每一個(gè)鍵值對,也就是 for
循環(huán):
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
for (key, value) in &scores {
println!("{key}: {value}");
}
}
HashMap和所有權(quán)
對于像 i32
這樣的實(shí)現(xiàn)了 Copy
trait 的類型,其值可以拷貝進(jìn)哈希 map。對于像 String
這樣擁有所有權(quán)的值,其值將被移動(dòng)而哈希 map 會成為這些值的所有者:
fn main() {
use std::collections::HashMap;
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
// 這里 field_name 和 field_value 不再有效,
// 嘗試使用它們看看會出現(xiàn)什么編譯錯(cuò)誤!
}
當(dāng) insert
調(diào)用將 field_name
和 field_value
移動(dòng)到哈希 map 中后,將不能使用這兩個(gè)綁定。
如果將值的引用插入哈希 map,這些值本身將不會被移動(dòng)進(jìn)哈希 map。但是這些引用指向的值必須至少在哈希 map 有效時(shí)也是有效的。
更新值
insert不僅可以插入一個(gè)鍵值對,還可以更新鍵值對。
map 有一個(gè)特有的 API,叫做 entry
,它獲取鍵對應(yīng)的Entry。Entry
代表了可能存在也可能不存在的值。Entry
的 or_insert
方法在鍵對應(yīng)的值存在時(shí)就返回這個(gè)值的可變引用,如果不存在則將參數(shù)作為新值插入并返回新值的可變引用:
fn main() {
use std::collections::HashMap;
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);
}
or_insert
方法返回這個(gè)鍵的值的一個(gè)可變引用(&mut V
)。這里我們將這個(gè)可變引用儲存在 count
變量中,所以為了賦值必須首先使用星號(*
)解引用 count:
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);
}
參考:文章來源:http://www.zghlxwxcb.cn/news/detail-726148.html
常見集合 - Rust 程序設(shè)計(jì)語言 簡體中文版文章來源地址http://www.zghlxwxcb.cn/news/detail-726148.html
到了這里,關(guān)于Rust常見集合的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!