第二节、集合
集合
集合可以包含多个值和多个不同类型的内容。
用向量来存储列表值
Rust 定义Veclet v: Vec<i32> = Vec::new();
vec!
宏来创建一个向量,这时候Rust会自动识别向量类型。
let v = vec![1, 2, 3];
更新向量
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
let mut v1 = vec![1, 2, 3];
v1.push(4)
读取向量
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {}", third);
match v.get(2) {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
The third element is 3
The third element is 3
超出范围的读取:
let v = vec![1, 2, 3, 4, 5];
let does_not_exist = &v[100]; //这个让程序执行报错
let does_not_exist = v.get(100); //因此要用这个方法,
要依次访问向量中的每个元素,我们将遍历所有元素,而不是使用索引一次访问一个。下面代码展示了如何使用for循环来获取对值向量中每个元素的不可变引用 i32并打印它们。
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
```
我们还可以迭代对可变向量中每个元素的可变引用,以便对所有元素进行更改。for清单 循环将添加50到每个元素。
```rust
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
借助枚举来存储多类型:
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
使用字符串存储 UTF-8 编码文本
在集合的章节讨论字符串,因为字符串是作为字节集合实现的,加上一些方法可以在这些字节被解释为文本时提供有用的功能。在本节中,我们将讨论String每种集合类型所具有的操作,例如创建、更新和读取。我们还将讨论与String 其他集合不同的方式,即索引到 String是如何因人和计算机解释 String数据的方式不同而变得复杂。
什么是字符串?
我们将首先定义术语string的含义。Rust 在核心语言中只有一种字符串类型,str即通常以借用形式看到的字符串切片&str。前面我们讨论了字符串切片,它是对存储在其他地方的一些 UTF-8 编码字符串数据的引用。例如,字符串文字存储在程序的二进制文件中,因此是字符串切片。
创建新字符串
let mut s = String::new();
s.push_str("os2edu");
也可以这样:
let data = "initial contents";
let s = data.to_string();
// the method also works on a literal directly:
let s = "initial contents".to_string();
或者这样:
let s = String::from("initial contents");
//支持各种语言
let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("你好");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");
字符串加法
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used
可以使用format格式化拼接字符串:
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
字符串索引
let s1 = String::from("hello");
let h = s1[0]; //这是错误的
let h = &s1[0];//这是可以的
字符串切片
let hello = "welcome to beijing";
let s = &hello[0..4];
let s1 = &hello[0..1]; //这是错误的,这时候s1是一个char,而不是string
迭代字符串
for c in hello.chars() {
println!("{}", c);
}
for b in hello.bytes() {
println!("{}", b);
}
HashMap
HashMap
创建HashMap
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
也可以用循环来插入HashMap
fn main() {
use std::collections::HashMap;
let teams_list = vec![
("中国队".to_string(), 100),
("美国队".to_string(),10),
("日本队".to_string(),50),
];
let mut teams_map = HashMap::new();
for team in &teams_list {
teams_map.insert(&team.0, team.1);
}
println!("{:?}",teams_map)
}
这里面的循环可以换一个方法用迭代器:
fn main() {
use std::collections::HashMap;
let teams_list = vec![
("中国队".to_string(), 100),
("美国队".to_string(),10),
("日本队".to_string(),50),
];
let teams_map: HashMap<_,_> = teams_list.into_iter().collect();
println!("{:?}",teams_map)
}
也可以写成这样:
use std::collections::HashMap;
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let mut scores: HashMap<_, _> =
teams.into_iter().zip(initial_scores.into_iter()).collect();
访问HashMap值
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);
采用for循环:
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);
}
重复插入会被覆盖
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
println!("{:?}", scores);
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是可以有返回值的,通过返回值可以更新里面的内容:
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}