集合(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);

  1. - 借助枚举来在向量中存储多种类型的值

enum SpreadsheetCell { Int(i32), Float(f64), Text(String), }

let row = vec![ SpreadsheetCell::Int(3), SpreadsheetCell::Text(String::from(“blue”)), SpreadsheetCell::Float(10.12), ];

  1. <a name="MMuGG"></a>
  2. # 2 字符串
  3. - 语言核心只有一种字符串类型,即str,字符串切片,通常以借用的形式出现,&str
  4. - String是标准库提供的字符串类型。标准库还提供了其他字符串类型,如OsString、OsStr、CString、CStr。
  5. <a name="TxJIf"></a>
  6. ## 2.1 创建字符串
  1. let s = String::new();
  2. let data = "initial contents";
  3. let s = data.to_string();
  4. let s = "initial contents".to_string();
  5. let s = String::from("initial contents");
  1. <a name="HxKFp"></a>
  2. ## 2.2 修改字符串

let mut s = String::from(“foo”); s.push_str(“bar”); println!(“{}”,s);

  1. let mut s1 = String::from("foo");
  2. let s2 = String::from("bar");
  3. s1.push_str(&s2);
  4. println!("{}",s1);
  5. let mut s = String::from("lo");
  6. s.push('l');
  7. println!("{}",s);
  1. <a name="911a95ed"></a>
  2. ## 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);

  1. <a name="lFnEV"></a>
  2. ## 2.4 使用format!宏执行拼接

let s1 = String::from(“Hello, “); let s2 = String::from(“world!”); let s3 = format!(“{}-{}”,s1,s2); println!(“{}”,s3);

  1. - 不允许对字符串进行取下标操作[],因为内部用UTF-8编码,对于多字节字符不好处理
  2. - 字符串切片也不好用,处理多字节字符不方便,如果指定的边界不在字符上,运行时会panic

fn string_demo5(){ let s1 = String::from(“China中国”); let s = &s1[0..7]; println!(“{}”,s); }

  1. <a name="lGIdb"></a>
  2. ## 2.5 遍历字符串

fn string_demo6(){ let s1 = “China中国”; for s in s1.chars(){ println!(“{}”,s); } for s in s1.bytes(){ println!(“{}”,s); } }

  1. <a name="clEQF"></a>
  2. # 3 HashMap
  3. <a name="gxBKd"></a>
  4. ## 3.1 新建Hash

use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from(“Blue”), 10); scores.insert(String::from(“Yellow”), 50);

  1. <a name="kEUoE"></a>
  2. ## 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();

  1. <a name="bdcc48ff"></a>
  2. ## 3.3 访问元素

// 取单个值 let team_name = String::from(“Blue”); let score = scores.get(&team_name); match score{ Some(val) => println!(“{}”,val), None => println!(“not found”), }

  1. // 遍历
  2. for (key, value) in &scores {
  3. println!("{}: {}", key, value);
  4. }
  1. <a name="BA353"></a>
  2. ## 3.4 更新元素

// 重复插入会替换已经存在的值 scores.insert(String::from(“Yellow”), 60); // 只在条目不存在的时候插入值 scores.entry(String::from(“Yellow”)).or_insert(70);

//—————— let text = “hello world wonderful world”;

  1. let mut map = HashMap::new();
  2. for word in text.split_whitespace() {
  3. let count = map.entry(word).or_insert(0);
  4. *count += 1;
  5. }
  6. println!("{:?}", map);

```

5 练习题一

main.rs