blog.dopana

Back

null 的发明者托尼·霍尔(Tony Hoare)曾将 null 称为他“价值十亿美元的错误”,因为空指针解引用引发了无数系统崩溃与严重安全漏洞。Rust 在编译阶段通过枚举 Option<T>Some(T) 变体彻底消除了 null 的存在。

像给 10 岁孩子解释:神秘快递盒#

Option<T> 想象成一个打包好的快递包裹:

  1. Some(玩具): 你撕开包装纸,发现里面确实装着一个真实的玩具。
  2. None: 拆开后发现这是一个空盒子,什么都没有。
graph TD
    Box["Option&lt;T&gt; (快递包裹)"] --> Check{"盒子里是否有物品?"}
    Check -->|是: 存在| SomeBranch["Some(具体值)<br/>(持有类型 T 的真实数据)"]
    Check -->|否: 为空| NoneBranch["None<br/>(表示值缺失状态)"]
    SomeBranch --> Unbox["使用 match / if let 安全解包读取"]
    NoneBranch --> Fallback["优雅处理空值,避免程序崩溃"]

在许多其他语言中,你可能会把一个空盒子当作玩具来把玩(例如在 usernull 时调用 user.getName()),从而触发运行时崩溃。而在 Rust 中,除非你主动显式“拆开包裹”,否则绝不可能直接使用 Some(T) 里面的数据。

Rust 中 Option<T> 的定义#

Option<T> 预置在 Rust 标准库 Prelude 中,可随处直接调用:

enum Option<T> {
    Some(T),
    None,
}
rust

因为 Option<T> 与类型 T 是两个完全独立的类型,编译器绝不会允许你把 Option<i8> 误当作 i8 进行数学运算:

let x: i8 = 5;
let y: Option<i8> = Some(5);

// let sum = x + y; // ❌ 编译报错: 不能将 Option<i8> 与 i8 直接相加
rust

处理 Some() 的 4 种惯用模式#

1. 使用 match 进行穷举匹配(最严谨清晰)#

2. 使用 if let 简洁解包#

当你只关心有值(Some)的情况并忽略 None 时:

src/main.rs
let config_timeout: Option<u64> = Some(3000);

if let Some(timeout) = config_timeout {
    println!("配置的超时时间: {timeout}ms");
}
rust

3. 配置默认兜底值:unwrap_orunwrap_or_else#

在生产代码中避免裸调 .unwrap(),应始终指定兜底默认值:

src/main.rs
let port: Option<u16> = None;

// 提供字面量默认值
let active_port = port.unwrap_or(8080);
println!("监听端口: {active_port}"); // 8080

// 通过闭包惰性计算默认值
let env_port = port.unwrap_or_else(|| {
    4000 + 4000
});
println!("计算得出的端口: {env_port}");
rust

4. 函数式组合子优雅链式变换#

无需手动解包即可对内部值进行变换:

src/main.rs
let raw_input: Option<&str> = Some("   rustacean   ");

let cleaned = raw_input
    .map(|s| s.trim())
    .filter(|s| !s.is_empty())
    .map(|s| s.to_uppercase());

println!("{cleaned:?}"); // Some("RUSTACEAN")
rust
graph LR
    Input["Some('   rustacean   ')"] -->|map trim| Trimmed["Some('rustacean')"]
    Trimmed -->|filter not empty| Filtered["Some('rustacean')"]
    Filtered -->|map uppercase| Final["Some('RUSTACEAN')"]

各语言空值机制对比#

语言表示方式安全等级遗漏检查时的后果
JavaScript / TypeScriptnull / undefined运行时 TypeError 崩溃
Java / C#null 指针中低NullPointerException
PythonNoneAttributeError: 'NoneType'
RustOption<T> (Some / None)编译期 100% 免疫编译报错,强迫显式处理

总结#

  • Some(value) 表示 Option<T> 中存在有效值。
  • None 表示该值缺失。
  • Rust 用 Option<T> 彻底替代了 null,消除了空指针导致的运行时异常。
  • 复杂分支用 match,单一提取用 if let,数据流变换用 .map().unwrap_or()

参考资料#