所以,你是 Ruby/Python 开发者,正在学习 Rust 的 Option 类型

发布: (2026年1月9日 GMT+8 14:00)
7 min read
原文: Dev.to

I’m happy to translate the article for you, but I need the actual text of the post. Could you please paste the content you’d like translated (excluding the source line you’ve already provided)? Once I have the article text, I’ll keep the source link unchanged and translate the rest into Simplified Chinese while preserving all formatting, markdown, and code blocks.

你所熟悉的

Python

user = find_user(id)
email = user.email.upper()  # fingers crossed

如果 userNone,你会得到一个 NoneType 错误。常用的变通办法:

email = user.email.upper() if user else None

Ruby

user = find_user(id)
email = user.email.upcase  # YOLO

或者,更安全一点:

email = user&.email&.upcase

两种语言都可能让你忘记检查,而这可能导致生产服务宕机。

Rust的“实际上,我们不要这么做”方法

Rust 没有 null。相反,你会得到一个 Option

let user: Option<_> = find_user(id);
  • Some(user) – 我们找到了某些东西
  • None – 没有东西

编译器不会允许你假装它总是 Some 你必须同时处理这两种情况,否则代码无法编译。经历短暂的学习曲线后,你会发现自己永远不再调试空指针崩溃了。

组合子(花哨的名字,简单的概念)

.map() – 当有值时执行某事

Python / Ruby

email = user.email.upper() if user else None

Rust

let email = user.map(|u| u.email.to_uppercase());

如果 userSome,闭包会执行;如果为 None,结果就是 None

.unwrap_or() – 提供回退值

Python

port = config.get('port') or 8080

Rust

let port = config.port.unwrap_or(8080);

直接的默认值处理。

.and_then() – 链式调用可能返回 None 的操作

Python / Ruby

result = None
if user:
    profile = get_profile(user.id)
    if profile:
        result = profile.email

Rust

let result = user
    .and_then(|u| get_profile(u.id))
    .and_then(|p| p.email);

每个 .and_then() 只有在前一步产生 Some 时才会运行;否则整个链会返回 None

? 运算符 – 在 NoneErr 时提前返回

fn get_user_email(id: u32) -> Result<String, Error> {
    let user = find_user(id)?;                     // 传播 Err/None
    let email = user.email.ok_or(Error::NoEmail)?; // 若为 None 则传播
    Ok(email.to_uppercase())
}

? 的含义是“如果这是一个错误(或 OptionNone),立即返回它;否则解包并继续”。它类似于 Ruby 的安全导航 (&.),但实际上会传播错误。

常见错误(我全都犯过)

❌ 不要这样做

let user = find_user(id).unwrap();   // Crashes on None

那相当于在 Rust 中忽略 nil 检查。

✅ 改为这样做

// Let the caller handle the error
let user = find_user(id)?;

// Or provide a sensible default
let user = find_user(id).unwrap_or_default();

// Or match explicitly
match find_user(id) {
    Some(u) => handle_user(u),
    None    => handle_missing(),
}

如果你真的确信该值一定存在,请使用 .expect("reason"),这样 panic 信息更有帮助:

let config = load_config().expect("config.toml must exist");

Quick Reference

你想要做的事如何实现
转换值`.map(
链式调用返回 Option‑returning calls`.and_then(
使用默认值.unwrap_or(default)
None/Err 时提前返回?
根据不同情况使用不同逻辑match … { Some(v) => …, None => … }
在测试中使用消息崩溃(仅限测试).expect("message")

FAQ

Q: 为什么这比仅仅检查 nil 更好?
A: 你不会忘记。编译器强制你处理这种情况,所以在生产环境中永远不会出现意外的空指针崩溃。

Q: 如果我确信它是 Some 怎么办?
A: 使用 .expect("explanation")。如果它真的 panic,消息会告诉你为什么你认为它是安全的。

Q: 这看起来比 Python/Ruby 更冗长。
A: 你并没有写 更多 的代码;你只是把错误处理显式化。在动态语言中,这些处理仍然存在——只是被隐藏且容易被忽视。一旦习惯了,你会欣赏这种安全网。

你自己: 你有多少次发布的代码没有正确检查 None/nil

Q: 我可以把所有东西都 unwrap 然后继续吗?

可以,但那你为什么要用 Rust?这就像买了配有安全气囊的汽车却把气囊禁用掉。核心目的就是在这些问题变成生产事故之前把它们捕获。

Real Talk

从 Ruby/Python 转到 Rust 时,Option 的处理一开始会让人觉得有点小题大做。你会感到恼火。你会抱怨编译器。你会想,为什么不能像普通人一样直接检查某个值是否为 None

然后有一天,你会意识到自己已经好几个月没有调试 NoneType 错误了。你重构了一些代码,编译器会捕获所有你忘记处理的新 None 情况的地方。你可以自信地发布,因为 只要能编译通过,那些错误路径实际上已经被处理了

这时,你恍然大悟。

学习曲线确实很陡,我不骗你。但编译器基本上在帮你做平时在生产环境中才会发现的代码审查。它的“烦人”就像一个好 senior 开发者指出你遗漏的各种边界情况一样。

总之,希望这能帮到你。去写点 Rust 吧。犯错吧。让编译器对你大喊大叫。你会做到的。

本文作者在前两周里曾绝对尝试对所有东西使用 .unwrap()(Cloudflare :)),并因此吃了大亏。

Back to Blog

相关文章

阅读更多 »

天才大师与他高效的笨蛋仆人

“为什么!为什么!呃!” 当我看到Sanni抓住一把自己的头发并用力拉扯时,我的嘴角上扬。我靠在椅子上,注视着她眼中凶狠的光芒……