Files
rust/Common-Use/readme.md
2025-10-05 23:51:24 +08:00

291 lines
7.2 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

非常好的问题 👏
`Option<&V>` 是 Rust 中非常核心的类型之一,理解它对你掌握 **Rust 的所有权系统****安全编程哲学** 都至关重要。
我们来一步步深入讲清楚,从原理到底层实现、再到各种用法与技巧。
---
# 🧩 一、什么是 `Option<T>`
## ✅ 定义
`Option<T>` 是一个**枚举类型**,定义在标准库中:
```rust
enum Option<T> {
Some(T),
None,
}
```
也就是说,它是一个「可能有值,也可能没有值」的容器。
* `Some(T)` 表示存在一个值;
* `None` 表示值不存在。
---
## 🧠 为什么要有 `Option<T>`
在很多语言(如 C/C++、Java缺失值通常用 `NULL``None`,但容易出错。
Rust 用 `Option<T>` 代替「空指针」,**在类型层面上强制你处理缺失的情况**。
这样编译器就能帮你防止空指针错误(`null pointer dereference`)。
---
# 🔍 二、`Option<&V>` 是什么?
`HashMap::get()` 等函数中,你会看到返回类型是:
```rust
Option<&V>
```
意思是:
> “可能返回一个指向值 `V` 的引用,如果 key 不存在,则返回 None。”
举个例子:
```rust
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("apple", 3);
let v1 = map.get("apple"); // Some(&3)
let v2 = map.get("banana"); // None
println!("{:?} {:?}", v1, v2);
}
```
输出:
```
Some(3) None
```
---
# 🧩 三、匹配(模式匹配)方式
最常见的处理方式是 **match**
```rust
match map.get("apple") {
Some(value) => println!("Found: {}", value),
None => println!("Not found"),
}
```
这种写法非常直观,但略显冗长,于是 Rust 提供了更优雅的写法👇
---
# ⚙️ 四、常见用法大全
## 1⃣ `is_some()` / `is_none()`
判断是否存在值:
```rust
if map.get("apple").is_some() {
println!("存在 apple");
}
```
---
## 2⃣ `unwrap()` / `unwrap_or()` / `unwrap_or_default()`
提取值:
```rust
let v = map.get("apple").unwrap(); // 若 None 则 panic!
let v = map.get("apple").unwrap_or(&0); // 若 None 则返回 &0
let v = map.get("apple").unwrap_or_default(); // 若 None 则返回默认值
```
> ⚠️ 不建议随意使用 `unwrap()`,除非你确信一定有值。
---
## 3⃣ `if let` 简写匹配
```rust
if let Some(v) = map.get("apple") {
println!("数量: {}", v);
}
```
`match` 简洁,常用于只关心 `Some` 的情况。
---
## 4⃣ `map()` —— 映射转换
`map()` 能把 `Option` 内的值加工成另一个类型:
```rust
let length = map.get("apple").map(|v| v * 2);
println!("{:?}", length); // Some(6)
```
若为 `None`,则结果仍是 `None`
---
## 5⃣ `and_then()` —— 链式调用
用于多层 Option 嵌套场景:
```rust
let result = map.get("apple")
.and_then(|v| Some(v * 10))
.and_then(|x| Some(x + 1));
println!("{:?}", result); // Some(31)
```
---
## 6⃣ `unwrap_or_else()` —— 延迟计算默认值
```rust
let v = map.get("banana").unwrap_or_else(|| {
println!("key 不存在,使用默认值");
&0
});
```
如果 key 不存在,执行闭包生成默认值。
---
## 7⃣ `as_ref()` / `as_mut()`
`Option<T>` 转换为 `Option<&T>``Option<&mut T>`
```rust
let opt = Some(String::from("hi"));
let ref_opt = opt.as_ref(); // Option<&String>
let mut_opt = opt.as_ref(); // Option<&mut String>
```
这在借用时非常实用,尤其是嵌套结构。
---
## 8⃣ `expect()` —— 自定义 panic 信息
```rust
let v = map.get("apple").expect("apple 不存在!");
```
如果是 `None`,会 panic 并显示 `"apple 不存在!"`
---
## 9⃣ `copied()` / `cloned()`
如果你要从 `Option<&T>` 提取出 `Option<T>`(复制/克隆),可以这样:
```rust
let map = HashMap::from([("a", 10)]);
let val = map.get("a").copied(); // Option<i32>
println!("{:?}", val); // Some(10)
```
区别:
* `.copied()` 要求 `T: Copy`
* `.cloned()` 要求 `T: Clone`
---
## 🔟 `unwrap_or_default()`
对简单类型(如 `i32``bool`)非常方便:
```rust
let map = HashMap::new();
let v: i32 = *map.get("x").unwrap_or_default(); // None -> 默认0
```
---
# 🧠 五、内部机制(零成本抽象)
Rust 的 `Option<T>` 在底层通常会被 **编译器优化为“无额外开销”** 的形式。
举个例子:
`Option<&T>` 通常和 `*const T` 的大小完全一样。
因为:
* `None` 会用空指针 `0` 表示;
* `Some(x)` 则用非零指针。
所以:
```rust
std::mem::size_of::<Option<&i32>>() == std::mem::size_of::<&i32>()
```
✅ 成立,说明 `Option<&T>` 没有额外开销。
---
# 🧩 六、总结表格
| 方法 | 作用 | 示例 | | |
| --------------------- | -------------------------------- | ------------------------- | - | ----------- |
| `is_some()` | 是否有值 | `opt.is_some()` | | |
| `is_none()` | 是否为空 | `opt.is_none()` | | |
| `unwrap()` | 直接取值(危险) | `opt.unwrap()` | | |
| `unwrap_or(x)` | 无值时返回 x | `opt.unwrap_or(0)` | | |
| `unwrap_or_default()` | 无值时返回默认值 | `opt.unwrap_or_default()` | | |
| `unwrap_or_else(f)` | 无值时调用函数生成 | `opt.unwrap_or_else( | | 0)` |
| `expect(msg)` | 无值时 panic带信息 | `opt.expect("错误")` | | |
| `map(f)` | 处理 Some 中的值 | `opt.map( | x | x+1)` |
| `and_then(f)` | 链式 Option 处理 | `opt.and_then( | x | Some(x+1))` |
| `as_ref()` | 转换为 Option<&T> | `opt.as_ref()` | | |
| `as_mut()` | 转换为 Option<&mut T> | `opt.as_mut()` | | |
| `copied()` | Option<&T> → Option<T>T: Copy | `opt.copied()` | | |
| `cloned()` | Option<&T> → Option<T>T: Clone | `opt.cloned()` | | |
---
# 🔚 七、一个综合示例
```rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);
scores.insert("Bob", 85);
let name = "Charlie";
let score = scores.get(name)
.copied() // Option<i32>
.unwrap_or_else(|| {
println!("{name} 不存在,使用默认分数");
60
});
println!("{name} 的分数是 {score}");
}
```
输出:
```
Charlie 不存在,使用默认分数
Charlie 的分数是 60
```
---
是否希望我接着帮你画一张「`Option<T>` 方法调用关系图(功能导图)」?
那张图能直观看出各种方法如何互相转换,非常适合记忆和快速查阅。