Rust 中的 Option、Result 和 ? 运算符

Option类型

在编程中,我们经常会遇到某个值或者某个数据域可能存在,可能不存在;如果存在,它才会包含某个值。在C/C++ 中,一般会使用 NULL 表示不存在这种情况,而 NULL 是很多异常和安全的祸根。Rust 从语言层面就删除了对 NULL 的支持,并在标准库中引入 Option 类型,用于表示上述那种可能存在可能不存在的情况。

Option 类型定义如下,它包含在 prelude 中,可以直接引用。

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

Result 类型

一个功能、服务的执行结果分为2类:(1)执行成功,返回执行结果;(2)执行失败,返回失败原因。在传统编程语言中,一般使用同一类型的返回值表示这两类结果,这会容易出现混淆。Rust 标准库引入 Result 类型,它是一个 enum 类型,用不同的枚举值类型表示两类结果。同时,基于Rust enum 类型的优点,将执行结果和失败原因包含在其中。借助特定声明式标记#[must_use] ,在代码没有处理这个结果时,给出编译警告,提供程序员优化代码。

Result 类型定义如下,它包含在 prelude 中,可以直接应用。

enum Result<T, E> {
   Ok(T),
   Err(E),
}

? 运算符

良好的 Rust 代码,很多时候,函数返回的是 Result 类型,如果每个调用都要处理一次返回值,代码就比较繁琐,很多时候,当调用的子函数返回的是 Err 时,我们只是想把这个 Err 传导到调用者函数,借助 ? 运算符,我们就可以实现这样功能。如果子函数返回的是 Ok 时,函数继续往下走;如果返回的是 Err,函数返回并返回这个 Err,由更上层的调用者负责具体处理 Result。

fn fun1() -> Result<int32, String> {

}

fn fun2() -> Result<int32, String> {

}

fn fun1() -> Result<int32, String> {

}


/// 传统处理方式
fn fun() -> Result<int32, String> {
	if let Err(e) = fun1() {
    return Err(e);
  }

	if let Err(e) = fun2() {
    return Err(e);
  }

	if let Err(e) = fun3() {
    return Err(e);
  }

	Ok(i)
}

/// 借助 ? 运算符
fn fun() -> Result<int32, String> {
	fun1()?;
  fun2()?;
  fun3()?;

	Ok(i)
}

/// 当然,在更上层的调用函数中,还是需要程序员处理这个Result的。比如
fn main() {

  // fun() 的调用者 main() 返回值不是 Result,就无法再向上传导了。
  // 或者fun() 的调用者需要主动对 Err 做处理时,就不要再直接向上传导。
	let ret = fun();

  match ret {
    Ok(i) => {
      println!("success, ret is {i}");
    }
    Err(e) => {
      println!("Fail, error reason is {e:}");
    }
  }
}

? 运算符同样适用于 Option,当遇到 None 时,直接返回并向上传导。