Skip to content

Ch 2: std::option - Option处理

Option<T> 是 Rust 中最常用的枚举类型之一,用于表示一个值可能存在或不存在。它是 Rust 类型系统安全的核心体现,强制开发者处理”空值”的情况。本章将详细讲解 Option 的常用方法,帮助你写出更加健壮的代码。

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

Option 消除了传统意义上的”空指针引用”,编译时强制检查空值情况。

3. unwrap 和 unwrap_unchecked - 解包值

Section titled “3. unwrap 和 unwrap_unchecked - 解包值”

unwrap 在有值时返回 Some,在 None 时 panic:

fn main() {
let some_value: Option<i32> = Some(42);
println!("{}", some_value.unwrap()); // 42
let none_value: Option<i32> = None;
// none_value.unwrap(); // thread 'main' panicked at 'called `Option::unwrap()` on a `None` value'
}

unwrap_or 提供默认值:

fn main() {
let none_value: Option<i32> = None;
// unwrap_or 在 None 时返回默认值
println!("{}", none_value.unwrap_or(0)); // 0
println!("{}", none_value.unwrap_or(100)); // 100
let some_value = Some(42);
println!("{}", some_value.unwrap_or(0)); // 42
}

unwrap_or_else 惰性求值默认值:

fn main() {
let none_value: Option<i32> = None;
// 闭包只在 None 时才调用
let result = none_value.unwrap_or_else(|| {
println!("计算默认值...");
expensive_computation()
});
}
fn expensive_computation() -> i32 {
42
}

map 在 Some 上应用函数,在 None 上直接返回 None:

方法签名:

pub fn map<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> U,

示例:

fn main() {
let some_number: Option<i32> = Some(5);
// 将 Option<i32> 转换为 Option<String>
let result = some_number.map(|n| n * 2);
println!("{:?}", result); // Some(10)
let none_number: Option<i32> = None;
let result = none_number.map(|n| n * 2);
println!("{:?}", result); // None
}

实用场景 - 字符串处理:

fn main() {
let some_name: Option<String> = Some(String::from("Alice"));
// 安全地获取字符串长度,无需检查 None
let length = some_name.map(|s| s.len());
println!("{:?}", length); // Some(5)
let no_name: Option<String> = None;
let length = no_name.map(|s| s.len());
println!("{:?}", length); // None
}

and_then(也称 flat_map)用于链式操作,当 Option 为 Some 时调用函数,返回新的 Option:

方法签名:

pub fn and_then<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> Option<U>,

示例:

fn main() {
let some_number: Option<i32> = Some(5);
// 返回新的 Option
let result = some_number.and_then(|n| {
if n > 0 {
Some(n * 2)
} else {
None
}
});
println!("{:?}", result); // Some(10)
// 返回 None 时会短路
let bad_number: Option<i32> = Some(-1);
let result = bad_number.and_then(|n| {
if n > 0 {
Some(n * 2)
} else {
None
}
});
println!("{:?}", result); // None
}

实用场景 - 嵌套查找:

#[derive(Debug)]
struct User {
name: String,
email: Option<String>,
}
fn main() {
let users = vec![
User { name: "Alice".to_string(), email: Some("alice@example.com".to_string()) },
User { name: "Bob".to_string(), email: None },
];
// 找到 Bob 并获取其邮箱
let bob_email = users.iter()
.find(|u| u.name == "Bob")
.and_then(|u| u.email.clone());
println!("{:?}", bob_email); // None
}

or_else 在 None 时执行闭包返回备选的 Option:

方法签名:

pub fn or_else<F>(self, f: F) -> Option<T>
where
F: FnOnce() -> Option<T>,

示例:

fn main() {
let none_value: Option<i32> = None;
// None 时返回备选值
let result = none_value.or_else(Some);
println!("{:?}", result); // None
let fallback = || {
println!("计算备选值...");
Some(42)
};
let result = none_value.or_else(fallback);
println!("{:?}", result); // Some(42)
}

ok_or 将 Option 转换为 Result<T, E>,None 变为 Err(E):

方法签名:

pub fn ok_or<E>(self, err: E) -> Result<T, E>

示例:

fn main() {
let some_value: Option<i32> = Some(42);
let result: Result<i32, &str> = some_value.ok_or("No value");
println!("{:?}", result); // Ok(42)
let none_value: Option<i32> = None;
let result: Result<i32, &str> = none_value.ok_or("No value");
println!("{:?}", result); // Err("No value")
}

实用场景 - parse 组合使用:

fn main() {
let strings = vec!["42", "hello", "100"];
for s in strings {
let num: Result<i32, _> = s.parse::<i32>().ok_or("Parse error");
println!("{:?}", num);
}
}

flatten 用于处理 Option<Option<T>> 的情况:

方法签名:

pub fn flatten(self) -> Option<T>
where
T: ~const Option<T>,

示例:

fn main() {
let nested: Option<Option<i32>> = Some(Some(42));
let flattened = nested.flatten();
println!("{:?}", flattened); // Some(42)
let nested_none: Option<Option<i32>> = Some(None);
let flattened = nested_none.flatten();
println!("{:?}", flattened); // None
let outer_none: Option<Option<i32>> = None;
let flattened = outer_none.flatten();
println!("{:?}", flattened); // None
}

实用场景 - 链式查找:

#[derive(Debug)]
struct Inner {
value: Option<i32>,
}
#[derive(Debug)]
struct Outer {
inner: Option<Inner>,
}
fn main() {
let data = Outer { inner: Some(Inner { value: Some(42) }) };
// 提取最内层的值
let value = data.inner
.flatten()
.map(|inner| inner.value)
.flatten();
println!("{:?}", value); // Some(42)
// 更简洁的写法
let value2 = data.inner
.and_then(|i| i.value);
println!("{:?}", value2); // Some(42)
}
#[derive(Debug)]
struct Config {
host: String,
port: Option<u16>,
}
impl Config {
fn new(host: Option<String>, port: Option<u16>) -> Result<Config, String> {
let host = host.ok_or("Missing host")?;
// map(port) 将 None 保持为 None,或 Some(port)
let port = port.ok_or("Missing port")?;
Ok(Config { host, port })
}
}
fn main() {
// 完整配置
let config = Config::new(
Some("example.com".to_string()),
Some(8080),
);
println!("{:?}", config); // Ok(Config { host: "example.com", port: 8080 })
// 缺失 port
let config = Config::new(
Some("example.com".to_string()),
None,
);
println!("{:?}", config); // Err("Missing port")
}
  1. unwrap 的危险性:在 None 时 panic,生产环境中应优先使用 unwrap_or、unwrap_or_else 或 ? 操作符。

  2. and_then vs map:map 转换值的类型,and_then 用于需要返回 Option 的场景(链式操作)。

  3. or_else vs or:or_else 接受闭包,惰性求值,适合计算成本较高的默认值。

  4. 使用 ? 操作符:Option 可以使用 ? 操作符进行错误传播,更符合习惯用法:

    fn get_config() -> Option<Config> {
    let host = host_from_env()?;
    let port = port_from_env()?;
    Some(Config { host, port })
    }
  5. flatten 的必要性:Option<Option<T>> 不自动降维,需要显式调用 flatten。

Option 是 Rust 处理”可能不存在”值的核心类型:

方法作用返回类型
unwrap解包,None 时 panicT
unwrap_or解包,None 时返回默认值T
map转换内部值Option<U>
and_then链式 Option 操作Option<U>
or_elseNone 时返回备选Option<T>
ok_or转换为 ResultResult<T, E>
flatten展平嵌套 OptionOption<T>

熟练运用这些方法,可以让你的代码既安全又简洁。