add chapter_3_15

This commit is contained in:
Davirain
2023-05-17 20:34:44 +08:00
parent 21eafe209a
commit 96aa22f1a4
9 changed files with 617 additions and 0 deletions

View File

@@ -13,6 +13,14 @@
- [所有权介绍](./chapter_3/chapter_3_7_1.md)
- [引用与借用](./chapter_3/chapter_3_7_2.md)
- [Slice类型](./chapter_3/chapter_3_7_3.md)
- [3.15 常见Collections](./chapter_3/chapter_3_15.md)
- [3.15.1 Vector](./chapter_3/chapter_3_15_1.md)
- [3.15.2 String](./chapter_3/chapter_3_15_2.md)
- [3.15.3 HashMap](./chapter_3/chapter_3_15_3.md)
- [3.15.4 HashSet](./chapter_3/chapter_3_15_4.md)
- [3.15.5 LinkedList](./chapter_3/chapter_3_15_5.md)
- [3.15.6 BTreeMap](./chapter_3/chapter_3_15_6.md)
- [3.15.7 BTreeSet](./chapter_3/chapter_3_15_7.md)
- [3.20 Rust并发编程](./chapter_3/chapter_3_20.md)
- [3.21 unsafe编程](./chapter_3/chapter_3_21.md)
- [Rust使用技巧]()

View File

@@ -0,0 +1,9 @@
# 3.15 常见Collections
- [3.15.1 Vector向量](./chapter_3_15_1.md)
- [3.15.2 String字符串](./chapter_3_15_2.md)
- [3.15.3 HashMap哈希映射](./chapter_3_15_3.md)
- [3.15.4 HashSet哈希集合](./chapter_3_15_4.md)
- [3.15.5 LinkedList链表](./chapter_3_15_5.md)
- [3.15.6 BTreeMapB 树映射)](./chapter_3_15_6.md)
- [3.15.7 BTreeSetB 树集合)](./chapter_3_15_7.md)

View File

@@ -0,0 +1,69 @@
# 3.15.1 Vector向量
Rust 中的 Vector向量是一个动态的、可增长的数组它可以存储一系列相同类型的元素。向量在连续的内存空间中存储元素这使得访问和修改元素非常快。以下是有关 Rust 向量的一些详细信息:
## 1. 创建 Vector
可以使用 Vec<T> 类型创建一个向量,其中 T 是存储在向量中的元素的类型。要创建一个新的空向量,可以使用 Vec::new() 方法。
```rust
let mut vec = Vec::new();
```
或者,可以使用宏 vec![] 初始化一个包含初始值的向量:
```rust
let vec = vec![1, 2, 3, 4, 5];
```
## 2. 添加元素:
可以使用 push() 方法向向量的末尾添加一个元素。
```rust
vec.push(6);
```
## 3.访问元素:
可以通过索引访问向量中的元素,类似于数组。请注意,尝试访问无效索引可能导致运行时错误。
```rust
let first = vec[0]; // 访问向量中的第一个元素
```
或者,可以使用 get() 方法安全地访问元素,它返回一个 Option 类型。如果指定的索引有效,则返回 Some(element),否则返回 None。
```rust
let first = vec.get(0); // 返回 Option<&T>
```
## 4. 遍历元素:
可以使用 for 循环遍历向量中的所有元素。
```rust
for element in &vec {
println!("Element: {}", element);
}
```
## 5. 删除元素:
可以使用 remove() 方法删除向量中指定索引处的元素。此操作将删除元素并将后续元素向前移动。
```rust
vec.remove(0); // 删除向量中的第一个元素
```
## 6. Vector 的容量和长度:
向量的长度是其中的元素数量,而容量是为这些元素分配的内存空间。向量会根据需要自动增长,但当长度超过容量时,它需要重新分配内存并复制元素到新内存区域。可以使用 len() 获取向量的长度,使用 capacity() 获取容量,还可以使用 shrink_to_fit() 方法减小容量以匹配当前长度。
## 7. 切片:
切片是对向量一部分元素的引用,可以用作轻量级的视图。要创建切片,可以使用范围语法:
```rust
let slice = &vec[1..4]; // 创建一个包含索引 1 到 3包括 1不包括 4的元素的切片
```
向量是 Rust 中使用非常广泛的集合类型,因为它提供了灵活性、性能和安全性。

View File

@@ -0,0 +1,78 @@
# 3.14.2 String字符串
Rust 中的 String字符串是一个可增长的、UTF-8 编码的字符串类型。它可以存储和处理文本数据。这里是关于 Rust 字符串的一些详细信息:
## 1. 创建 String
可以使用 String::new() 创建一个新的空字符串,或者使用 String::from() 从字符串字面量创建字符串。
```rust
let mut s = String::new();
let s = String::from("hello");
```
还可以使用 to_string() 方法将基本类型转换为字符串。
```rust
let num = 42;
let s = num.to_string();
```
## 2. 字符串长度:
字符串的长度是其 UTF-8 编码的字节的数量,而不是 Unicode 字符的数量。可以使用 len() 方法获取字符串的长度。
```rust
let len = s.len();
```
## 3. 字符串拼接:
有多种方法可以将字符串拼接在一起。例如,可以使用 + 运算符或 format! 宏。
```rust
let s1 = String::from("hello");
let s2 = String::from("world");
let s3 = s1 + " " + &s2;
```
或者使用 push_str() 方法将字符串附加到现有字符串。
```rust
let mut s = String::from("hello");
s.push_str(" world");
```
## 4. 访问字符:
由于 Rust 字符串是 UTF-8 编码的,不能直接使用索引访问单个字符。但是,可以使用迭代器遍历字符串中的字符。
```rust
for c in s.chars() {
println!("{}", c);
}
```
还可以使用 bytes() 方法遍历字节,或者使用 char_indices() 方法获取字符及其对应的字节索引。
## 5.字符串切片:
可以使用范围语法创建字符串的切片,它表示原始字符串中一部分的引用。需要确保范围边界位于有效的 UTF-8 字符边界上,否则将导致运行时错误。
```rust
let s = String::from("hello");
let slice = &s[0..4]; // 获取字符串前 4 个字节的切片
```
## 6. 修改字符串:
可以使用 push() 方法将一个字符添加到字符串的末尾,或者使用 insert()
方法将字符插入指定的字节位置。
```rust
let mut s = String::from("hello");
s.push('!');
s.insert(5, ',');
```
注意,字符串插入操作可能需要 O(n) 时间,其中 n 是插入位置之后的字节数。
## 7. 删除字符串中的字符:
可以使用 pop() 方法删除并返回字符串末尾的字符,或者使用 remove() 方法删除并返回指定字节位置处的字符。
```rust
let mut s = String::from("hello");
s.pop();
s.remove(0);
```
Rust 的字符串处理非常关注编码安全性和性能,因此,与其他编程语言相比,某些操作可能有所不同。然而,这使得 Rust 能够提供安全、高效的字符串操作。

View File

@@ -0,0 +1,102 @@
# 3.15.3 HashMap哈希映射
Rust 中的 HashMap哈希映射是一个基于键值对的无序集合它提供了高效的查找、插入和删除操作。HashMap 使用哈希函数将键映射到相应的存储桶,这使得大部分操作具有 O(1) 的平均时间复杂度。以下是有关 Rust HashMap 的一些详细信息:
## 1. 创建 HashMap
要创建一个新的空 HashMap可以使用 HashMap::new() 方法。需要导入 std::collections::HashMap 模块以使用 HashMap。
```rust
use std::collections::HashMap;
let mut map = HashMap::new();
```
## 2. 插入键值对:
可以使用 insert() 方法向 HashMap 中添加键值对。如果使用相同的键插入新值,旧值将被替换。
```rust
map.insert("one", 1);
map.insert("two", 2);
```
## 3. 访问值:
可以使用 get() 方法根据键查找值。此方法返回一个 Option<&V> 类型,如果找到键,则返回 Some(&value),否则返回 None。
```rust
let value = map.get("one"); // 返回 Option<&V>
```
还可以使用 get_mut() 方法获取可变引用。
## 4. 遍历键值对:
可以使用 for 循环遍历 HashMap 中的所有键值对。
```rust
for (key, value) in &map {
println!("{}: {}", key, value);
}
```
## 5. 删除键值对:
可以使用 remove() 方法根据键删除键值对。此方法返回一个 Option<V> 类型,如果找到并删除了键值对,则返回 Some(value),否则返回 None。
```rust
map.remove("one"); // 删除键为 "one" 的键值对
```
## 6. 检查键是否存在:
可以使用 contains_key() 方法检查 HashMap 中是否存在指定的键。
```rust
let has_key = map.contains_key("one"); // 返回布尔值
```
## 7. 更新值:
可以使用 entry() 方法与 or_insert() 方法结合,更新 HashMap 中的值或插入新值。
```rust
*map.entry("three").or_insert(3) += 1;
```
## 8. HashMap 的容量和长度:
可以使用 len() 方法获取 HashMap 中的键值对数量,使用 capacity() 方法获取容量。还可以使用 shrink_to_fit() 方法减小容量以匹配当前长度。
## 9. 默认哈希器:
Rust 的 HashMap 默认使用一个加密安全的哈希函数SipHash它在防止哈希碰撞攻击方面表现良好但可能不如其他哈希函数快。可以通过为 HashMap 类型提供自定义的哈希器来改变默认行为。
```rust
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use twox_hash::XxHash64;
type FastHashMap<K, V> = HashMap<K, V, BuildHasherDefault<XxHash64>>;
let mut map: FastHashMap<&str, i32> = FastHashMap::default();
map.insert("one", 1);
map.insert("two", 2);
```
在这个例子中,我们使用了 twox_hash 库中的 XxHash64 哈希函数,它通常比默认的 SipHash 更快。请注意,使用自定义哈希函数可能会降低安全性,因此要确保在明确了解潜在风险的情况下进行更改。
## 10. 合并两个 HashMap
可以使用 extend() 方法将另一个 HashMap 的键值对添加到当前 HashMap 中。如果存在重复的键,目标 HashMap 中的值将被源 HashMap 中的值覆盖。
```rust
let mut map1 = HashMap::new();
map1.insert("one", 1);
map1.insert("two", 2);
let mut map2 = HashMap::new();
map2.insert("two", 22);
map2.insert("three", 3);
map1.extend(map2); // 将 map2 中的键值对添加到 map1
```
这样map1 将包含键值对 "one" -> 1, "two" -> 22 和 "three" -> 3。
总之Rust 中的 HashMap 是一个功能丰富且性能优越的键值对集合,非常适合在需要快速查找和修改操作的场景中使用。

View File

@@ -0,0 +1,103 @@
# 3.15.4 HashSet哈希集合
Rust 中的 HashSet哈希集合是一种无序的、不含重复元素的集合。它使用哈希函数将元素映射到相应的存储桶这使得大部分操作具有 O(1) 的平均时间复杂度。以下是有关 Rust HashSet 的一些详细信息:
## 1. 创建 HashSet
要创建一个新的空 HashSet可以使用 HashSet::new() 方法。需要导入 std::collections::HashSet 模块以使用 HashSet。
```rust
use std::collections::HashSet;
let mut set = HashSet::new();
```
## 2. 添加元素:
可以使用 insert() 方法向 HashSet 中添加元素。如果元素已存在,则此方法将返回 false否则返回 true。
```rust
set.insert(1);
set.insert(2);
set.insert(3);
```
## 3. 检查元素是否存在:
可以使用 contains() 方法检查 HashSet 中是否存在指定的元素。
```rust
let contains = set.contains(&1); // 返回布尔值
```
## 4. 删除元素:
可以使用 remove() 方法删除 HashSet 中的元素。此方法返回一个 bool 类型,如果找到并删除了元素,则返回 true否则返回 false。
```rust
set.remove(&1); // 删除元素 1
```
## 5. 遍历元素:
可以使用 for 循环遍历 HashSet 中的所有元素。
```rust
for element in &set {
println!("{}", element);
}
```
## 6. HashSet 的长度:
可以使用 len() 方法获取 HashSet 中的元素数量。还可以使用 is_empty() 方法检查 HashSet 是否为空。
## 7. 集合操作:
HashSet 支持一些基本的集合操作,如并集、交集、差集和对称差集。
- 并集union返回一个新的 HashSet包含两个集合中的所有元素。
```rust
let set1: HashSet<_> = [1, 2, 3].iter().cloned().collect();
let set2: HashSet<_> = [3, 4, 5].iter().cloned().collect();
let union: HashSet<_> = set1.union(&set2).cloned().collect();
```
- 交集intersection返回一个新的 HashSet包含两个集合中共有的元素。
```rust
let intersection: HashSet<_> = set1.intersection(&set2).cloned().collect();
```
- 差集difference返回一个新的 HashSet包含第一个集合中存在但第二个集合中不存在的元素。
```rust
let difference: HashSet<_> = set1.difference(&set2).cloned().collect();
```
- 对称差集symmetric_difference返回一个新的 HashSet包含两个集合中唯一的元素也就是只存在于一个集合中的元素
```rust
let symmetric_difference: HashSet<_> = set1.symmetric_difference(&set2).cloned().collect();
```
## 8. 清空 HashSet
可以使用 clear() 方法删除 HashSet 中的所有元素。
```rust
set.clear(); // 清空 HashSet
```
总的来说Rust 中的 HashSet提供了一种高效且易于使用的无序集合实现适用于需要快速查找、添加和删除操作的场景。由于 HashSet 的底层实现基于哈希表,它能够在大部分情况下为这些操作提供 O(1) 的平均时间复杂度。
与 HashMap 类似Rust 的 HashSet 默认使用一个加密安全的哈希函数SipHash以防止哈希碰撞攻击。如果需要更高的性能可以考虑使用自定义哈希器但要确保在明确了解潜在风险的情况下进行更改。这是一个使用自定义哈希器的例子
```rust
use std::collections::HashSet;
use std::hash::BuildHasherDefault;
use twox_hash::XxHash64;
type FastHashSet<T> = HashSet<T, BuildHasherDefault<XxHash64>>;
let mut set: FastHashSet<i32> = FastHashSet::default();
set.insert(1);
set.insert(2);
```
在这个例子中,我们使用了 twox_hash 库中的 XxHash64 哈希函数,它通常比默认的 SipHash 更快。

View File

@@ -0,0 +1,80 @@
# 3.15.5 LinkedList链表
Rust 中的 LinkedList链表是一种线性数据结构它由一系列相互连接的节点组成。每个节点都包含一个元素和指向前一个节点和后一个节点的指针。这是有关 Rust LinkedList 的一些详细信息:
## 1. 创建 LinkedList
要创建一个新的空 LinkedList可以使用 LinkedList::new() 方法。需要导入 std::collections::LinkedList 模块以使用 LinkedList。
```rust
use std::collections::LinkedList;
let mut list = LinkedList::new();
```
## 2. 添加元素:
可以使用 push_front() 和 push_back() 方法将元素添加到链表的开头和结尾。
```rust
list.push_front(1);
list.push_back(2);
```
## 3. 访问元素:
可以使用 front() 和 back() 方法分别访问链表的第一个和最后一个元素。这些方法返回一个 Option<&T> 类型,如果链表不为空,则返回 Some(&element),否则返回 None。
```rust
let first_element = list.front(); // 返回 Option<&T>
let last_element = list.back(); // 返回 Option<&T>
```
还可以使用 front_mut() 和 back_mut() 方法获取可变引用。
## 4. 删除元素:
可以使用 pop_front() 和 pop_back() 方法分别删除并返回链表的第一个和最后一个元素。这些方法返回一个 Option<T> 类型,如果链表不为空且成功删除元素,则返回 Some(element),否则返回 None。
```rust
list.pop_front(); // 删除并返回第一个元素
list.pop_back(); // 删除并返回最后一个元素
```
## 5. 遍历元素:
可以使用 iter() 方法遍历链表中的所有元素。iter_mut() 方法可用于遍历可变引用。
```rust
for element in list.iter() {
println!("{}", element);
}
```
## 6. 链表长度:
可以使用 len() 方法获取链表中的元素数量。还可以使用 is_empty() 方法检查链表是否为空。
## 7. 清空链表:
可以使用 clear() 方法删除链表中的所有元素。
```rust
list.clear(); // 清空链表
```
## 8. 分割链表:
可以使用 split_off() 方法在指定索引处分割链表。此操作会将链表分成两个链表,前一个链表包含指定索引之前的元素,后一个链表包含指定索引及之后的元素。
```rust
let mut list1 = LinkedList::new();
list1.push_back(1);
list1.push_back(2);
list1.push_back(3);
let list2 = list1.split_off(1);
```
这样list1 将包含元素 1而 list2 将包含元素 2 和 3。
总之Rust 中的 LinkedList 提供了一种基于节点的线性数据结构它适用于需要快速插入和删除操作的场景。然而对于许多其他用途如随机访问和查找操作链表通常比数组或向量Vector等基于连续内存的数据结构性能差。这是因为链表的元素在内存中是分散存储的这会导致较差的缓存局部性cache locality。而连续内存数据结构在许多情况下可以更有效地利用 CPU 缓存,从而提高性能。
当考虑使用链表时,务必评估其适用性,并与其他数据结构(如 Vector进行比较。在某些情况下链表可能是一个很好的选择特别是当插入和删除操作的性能比访问和查找操作更重要时。然而在许多场景中使用基于连续内存的数据结构会带来更好的性能和更简单的代码。

View File

@@ -0,0 +1,71 @@
# 3.15.6 BTreeMapB 树映射)
Rust 中的 BTreeMapB 树映射)是一种自平衡的有序映射数据结构,它以 B 树的形式存储键值对。BTreeMap 具有对数级的时间复杂度,这使得它在需要维护键的顺序时非常有效。以下是有关 Rust BTreeMap 的一些详细信息:
## 1. 创建 BTreeMap
要创建一个新的空 BTreeMap可以使用 BTreeMap::new() 方法。需要导入 std::collections::BTreeMap 模块以使用 BTreeMap。
```rust
use std::collections::BTreeMap;
let mut map = BTreeMap::new();
```
## 2. 添加元素:
可以使用 insert() 方法向 BTreeMap 中添加键值对。如果键已存在,则此方法将返回 Some(old_value),否则返回 None。
```rust
map.insert("one", 1);
map.insert("two", 2);
map.insert("three", 3);
```
## 3. 访问元素:
可以使用 get() 方法根据键查找对应的值。此方法返回一个 Option<&V> 类型,如果找到键,则返回 Some(&value),否则返回 None。
```rust
let value = map.get("one"); // 返回 Option<&V>
```
还可以使用 get_mut() 方法获取可变引用。
## 4. 删除元素:
可以使用 remove() 方法删除 BTreeMap 中的键值对。此方法返回一个 Option<V> 类型,如果找到并删除了键值对,则返回 Some(value),否则返回 None。
```rust
map.remove("one"); // 删除键为 "one" 的键值对
```
## 5. 遍历元素:
可以使用 iter() 方法遍历 BTreeMap 中的所有键值对。遍历顺序按键的顺序进行。iter_mut() 方法可用于遍历可变引用。
```rust
for (key, value) in map.iter() {
println!("{}: {}", key, value);
}
```
## 6. BTreeMap 的长度:
可以使用 len() 方法获取 BTreeMap 中的键值对数量。还可以使用 is_empty() 方法检查 BTreeMap 是否为空。
## 7. 最小和最大键:
可以使用 first_key_value() 和 last_key_value() 方法分别获取 BTreeMap 中具有最小和最大键的键值对。这些方法返回一个 Option<(&K, &V)> 类型,如果找到键值对,则返回 Some((&key, &value)),否则返回 None。
```rust
let min_key_value = map.first_key_value(); // 返回 Option<(&K, &V)>
let max_key_value = map.last_key_value(); // 返回 Option<(&K, &V)>
```
## 8. 范围查询:
可以使用 range() 方法查询 BTreeMap 中某个范围内的键值对。例如,可以查询所有键大于等于 "one" 且小于等于 "three" 的键值对:
```rust
for (key, value) in map.range("one".."three") {
println!("{}: {}", key, value);
}
```

View File

@@ -0,0 +1,97 @@
# 3.15.7 BTreeSetB 树集合)
Rust 中的 BTreeSetB 树集合)是一种自平衡的有序集合数据结构,它以 B 树的形式存储元素。BTreeSet 具有对数级的时间复杂度,这使得它在需要维护元素顺序时非常有效。以下是有关 Rust BTreeSet 的一些详细信息:
## 1. 创建 BTreeSet
要创建一个新的空 BTreeSet可以使用 BTreeSet::new() 方法。需要导入 std::collections::BTreeSet 模块以使用 BTreeSet。
```rust
use std::collections::BTreeSet;
let mut set = BTreeSet::new();
```
## 2. 添加元素:
可以使用 insert() 方法向 BTreeSet 中添加元素。如果元素已存在,则此方法将返回 false否则返回 true。
```rust
set.insert(1);
set.insert(2);
set.insert(3);
```
## 3. 检查元素是否存在:
可以使用 contains() 方法检查 BTreeSet 中是否存在指定的元素。
```rust
let contains = set.contains(&1); // 返回布尔值
```
## 4. 删除元素:
可以使用 remove() 方法删除 BTreeSet 中的元素。此方法返回一个 bool 类型,如果找到并删除了元素,则返回 true否则返回 false。
```rust
set.remove(&1); // 删除元素 1
```
## 5. 遍历元素:
可以使用 for 循环遍历 BTreeSet 中的所有元素。遍历顺序按元素的顺序进行。
```rust
for element in &set {
println!("{}", element);
}
```
## 6. BTreeSet 的长度:
可以使用 len() 方法获取 BTreeSet 中的元素数量。还可以使用 is_empty() 方法检查 BTreeSet 是否为空。
## 7. 集合操作:
BTreeSet 支持一些基本的集合操作,如并集、交集、差集和对称差集。
- 并集union返回一个新的 BTreeSet包含两个集合中的所有元素。
```rust
let set1: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
let set2: BTreeSet<_> = [3, 4, 5].iter().cloned().collect();
let union: BTreeSet<_> = set1.union(&set2).cloned().collect();
```
- 交集intersection返回一个新的 BTreeSet包含两个集合中共有的元素。
```rust
let intersection: BTreeSet<_> = set1.intersection(&set2).cloned().collect();
```
- 差集difference返回一个新的 BTreeSet包含第一个集合中存在但第二个集合中不存在的元素。
```rust
let difference: BTreeSet<_> = set1.difference(&set2).cloned().collect();
```
- 对称差集symmetric_difference返回一个新的 BTreeSet包含两个集合中唯一的元素也就是只存在于一个集合中的元素
```rust
let symmetric_difference: BTreeSet<_> = set1.symmetric_difference(&set2).cloned().collect();
```
## 8. 最小和最大元素:
可以使用 first() 和 last() 方法分别获取 BTreeSet 中的最小和最大元素。这些方法返回一个 Option<&T> 类型,如果找到元素,则返回 Some(&element),否则返回 None。
```rust
let min_element = set.first(); // 返回 Option<&T>
let max_element = set.last(); // 返回 Option<&T>
```
## 9. 范围查询:
可以使用 range() 方法查询 BTreeSet 中某个范围内的元素。例如,可以查询所有大于等于 1 且小于等于 3 的元素:
```rust
for element in set.range(1..=3) {
println!("{}", element);
}
```
## 10. 清空 BTreeSet
可以使用 clear() 方法删除 BTreeSet 中的所有元素。
```rust
set.clear(); // 清空 BTreeSet
```
总之Rust 中的 BTreeSet 提供了一种有序集合数据结构,适用于需要维护元素顺序以及执行集合操作的场景。与 BTreeMap 类似BTreeSet 具有对数级的时间复杂度,这使得它在需要维护元素顺序时非常有效。然而,在需要快速查找、添加和删除操作的场景中,使用基于哈希表的数据结构(如 HashSet可能更适合。