集合(collections)类型可以包含多个值,集合元素是存储在堆中的,元素个数可以在运行中增加或者减少。本章介绍向量(vector)、字符串(String)和散列映射(HashMap),其他集合类型请参考标准库的集合文档。
1 向量
- 向量由标准库中的泛型Vec实现
- 创建空的vector: let v: Vec = Vec::new(); 必须指定类型
- 通过vec!宏创建vector: let v = vec![1, 2, 3]; 无需指定类型,因为可通过初始元素类型(i32)推断出类型
- 更新vector: v.push(4)
- 获取元素: &v[2] 下标越界时会panic
- 获取元素: v.get(20) 返回类型为Option<&T> 下标越界时返回None,不会panic
- 这段代码编译通不过: 因为 first 为元素的不可变引用;而push方法可能会导致内存重新分配,即要求可变引用``` let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0];
v.push(6);
- 借助枚举来在向量中存储多种类型的值
enum SpreadsheetCell { Int(i32), Float(f64), Text(String), }
let row = vec![ SpreadsheetCell::Int(3), SpreadsheetCell::Text(String::from(“blue”)), SpreadsheetCell::Float(10.12), ];
<a name="MMuGG"></a>
# 2 字符串
- 语言核心只有一种字符串类型,即str,字符串切片,通常以借用的形式出现,&str
- String是标准库提供的字符串类型。标准库还提供了其他字符串类型,如OsString、OsStr、CString、CStr。
<a name="TxJIf"></a>
## 2.1 创建字符串
let s = String::new();
let data = "initial contents";
let s = data.to_string();
let s = "initial contents".to_string();
let s = String::from("initial contents");
<a name="HxKFp"></a>
## 2.2 修改字符串
let mut s = String::from(“foo”); s.push_str(“bar”); println!(“{}”,s);
let mut s1 = String::from("foo");
let s2 = String::from("bar");
s1.push_str(&s2);
println!("{}",s1);
let mut s = String::from("lo");
s.push('l');
println!("{}",s);
<a name="911a95ed"></a>
## 2.3 拼接字符串
let s1 = String::from(“Hello, “); let s2 = String::from(“world!”); let s3 = s1 + &s2; // 注意运算符+的签名: fn add(self, s: &str) -> String // 1 add 获取了s1的所有权以及s2的所有权,返回结果字符串的所有权,执行完成后 s1 不再有效 // 2 add 第二个参数类型为 &str,但是实参 &s2 的类型是 &String,不匹配.这里 &String 可以 // 被强制转型(coerced)为&str,系统内部使用了 解引用强制多态(deref coercion)技术. println!(“{}”,s3); println!(“{}”,s2); //println!(“{}”,s1);
<a name="lFnEV"></a>
## 2.4 使用format!宏执行拼接
let s1 = String::from(“Hello, “); let s2 = String::from(“world!”); let s3 = format!(“{}-{}”,s1,s2); println!(“{}”,s3);
- 不允许对字符串进行取下标操作[],因为内部用UTF-8编码,对于多字节字符不好处理
- 字符串切片也不好用,处理多字节字符不方便,如果指定的边界不在字符上,运行时会panic
fn string_demo5(){ let s1 = String::from(“China中国”); let s = &s1[0..7]; println!(“{}”,s); }
<a name="lGIdb"></a>
## 2.5 遍历字符串
fn string_demo6(){ let s1 = “China中国”; for s in s1.chars(){ println!(“{}”,s); } for s in s1.bytes(){ println!(“{}”,s); } }
<a name="clEQF"></a>
# 3 HashMap
<a name="gxBKd"></a>
## 3.1 新建Hash
use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from(“Blue”), 10); scores.insert(String::from(“Yellow”), 50);
<a name="kEUoE"></a>
## 3.2 拼接集合类型形成Hash
let teams = vec![String::from(“Blue”), String::from(“Yellow”)]; let initialscores = vec![10, 50]; let scores: HashMap<, _> = teams.iter().zip(initial_scores.iter()).collect();
<a name="bdcc48ff"></a>
## 3.3 访问元素
// 取单个值 let team_name = String::from(“Blue”); let score = scores.get(&team_name); match score{ Some(val) => println!(“{}”,val), None => println!(“not found”), }
// 遍历
for (key, value) in &scores {
println!("{}: {}", key, value);
}
<a name="BA353"></a>
## 3.4 更新元素
// 重复插入会替换已经存在的值 scores.insert(String::from(“Yellow”), 60); // 只在条目不存在的时候插入值 scores.entry(String::from(“Yellow”)).or_insert(70);
//—————— 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);
```