Wang's blog

八、标准库 - 常用集合类型

Published on

Vec

Vec是长度可变的数组,它在堆上分配空间,且能自动进行内存管理,类似于C++的std::vector。一个Vec包含3个参数:

  • 数据指针
  • 长度
  • 容量
// 建立空Vec
let v: Vec<i32> = Vec::new();

// 使用初始值建立Vec
let v = vec![1, 2, 3];

// 添加值
v.push(4);

// 获取值
let third: &i32 = &v[2];
let third: Option<&i32> = v.get(2);

// 迭代值
for i in &v {
    println!("{i}");
}
for i in &mut v {
    *i += 50;
}

String

String是在堆上分配空间的动态字符串类型(区别于内置静态字符串类型&str),类似于C++的std::string。String底层存储使用Vec<u8>类型,但是保证总是有效的UTF8编码字符串。因此String中每个字符的大小不一致,需要小心使用。

// 建立空String
let mut s = String::new();

// 将&str转换为String
let s = "initial contents".to_string();
let s = String::from("initial contents");

// 追加内容
let mut s = String::from("foo");
s.push_str("bar");

// 使用+操作符拼接
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;

// 使用format宏格式化
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{s1}-{s2}-{s3}");

// 切片。String不支持索引,如hello[0],但是支持切片。由于每个字符长度不一,因此需要额外注意
let s = &hello[0..4];

// 迭代所有字符
for c in "Зд".chars() {
    println!("{c}");
}

// 迭代所有字节
for b in "Зд".bytes() {
    println!("{b}");
}

HashMap

HashMap用于储存键-值对,类似于C++的std::map。

// 建立空HashMap
let mut scores = HashMap::new();

// 添加值/覆盖值
scores.insert(String::from("Blue"), 10);

// 根据键获取值
let team_name = String::from("Blue");
let score = scores.get(&team_name).copied().unwrap_or(0);

// 迭代键-值对
for (key, value) in &scores {
    println!("{key}: {value}");
}

// 获取entry,根据entry可进一步进行不同的操作
let entry = scores.entry(String::from("Yellow"));

自定义键类型

可以使用任何实现了Eq与Hash特性的类型作为HashMap的键类型。

HashSet

HashSet<T>实际上是HashMap<T, ()>的包装器,用于存储不重复的元素。它有4个基本操作(全部返回迭代器):

  • union:获取两个集合中的全部不同元素
  • difference:获取在第一个集合中,但不在第二个集合中的元素
  • intersection:获取同时在两个集合中的元素
  • symmetric_difference:获取在一个集合中,但不同时在两个集合中的元素