rust学习-Option与Result

rust学习-Option与Result

  • [1. Option 类型](#1. Option 类型)
    • [1.1 什么是 Option?](#1.1 什么是 Option?)
    • [1.2 创建 Option](#1.2 创建 Option)
    • [1.3 处理 Option 的基本方法](#1.3 处理 Option 的基本方法)
      • [使用 match 处理](#使用 match 处理)
      • [使用 if let 处理](#使用 if let 处理)
    • [1.4 Option 的常用方法](#1.4 Option 的常用方法)
      • [unwrap 系列](#unwrap 系列)
      • [map 和 and_then](#map 和 and_then)
      • filter
      • [or 和 or_else](#or 和 or_else)
      • [get_or_insert 系列](#get_or_insert 系列)
    • [1.5 Option 的转换方法](#1.5 Option 的转换方法)
  • [2. Result 类型](#2. Result 类型)
    • [2.1 什么是 Result?](#2.1 什么是 Result?)
    • [2.2 创建 Result](#2.2 创建 Result)
    • [2.3 自定义错误类型](#2.3 自定义错误类型)
    • [2.4 Result 的常用方法](#2.4 Result 的常用方法)
      • [unwrap 系列](#unwrap 系列)
      • [map 系列](#map 系列)
      • [and_then 和 or_else](#and_then 和 or_else)
      • [错误传播:? 运算符](#错误传播:? 运算符)
    • [2.5 组合多个 Result](#2.5 组合多个 Result)
  • [3. 组合处理 Option 和 Result](#3. 组合处理 Option 和 Result)
    • [3.1 Option 和 Result 的相互转换](#3.1 Option 和 Result 的相互转换)
    • [3.2 transpose 方法](#3.2 transpose 方法)
    • [3.3 处理嵌套类型](#3.3 处理嵌套类型)
  • [4. 高级用法与模式](#4. 高级用法与模式)
    • [4.1 自定义错误类型和 thiserror 库](#4.1 自定义错误类型和 thiserror 库)
    • [4.2 anyhow 库用于应用程序错误处理](#4.2 anyhow 库用于应用程序错误处理)
    • [4.3 模式匹配的高级用法](#4.3 模式匹配的高级用法)
  • [5. 实际应用示例](#5. 实际应用示例)
    • [5.1 配置文件解析](#5.1 配置文件解析)
    • [5.2 数据库查询模拟](#5.2 数据库查询模拟)
  • [6. 最佳实践](#6. 最佳实践)
    • [6.1 何时使用 Option vs Result](#6.1 何时使用 Option vs Result)
    • [6.2 错误处理策略](#6.2 错误处理策略)
    • [6.3 性能考虑](#6.3 性能考虑)

Option 和 Result 是 Rust 中处理可能缺失的值和可能失败的操作的两个核心枚举类型。这是 Rust的安全哲学的一种体现:编译时强制错误处理。

1. Option :表示值可能存在 (Some(T)) 或不存在 (None)
2. Result<T, E>:表示操作可能成功 (Ok(T)) 或失败 (Err(E))

1. Option 类型

1.1 什么是 Option?

Option 是一个枚举,表示一个值可能存在 (Some) 或不存在 (None)。

rust 复制代码
enum Option<T> {
    Some(T),  // 包含一个值 T
    None,     // 不包含任何值
}

1.2 创建 Option

rust 复制代码
fn main() {
    // 创建 Some 值
    let some_number = Some(5);
    let some_string = Some("hello");
    
    // 创建 None 值 - 必须指定类型
    let absent_number: Option<i32> = None;
    
    // 使用 Option::Some 和 Option::None
    let x = Option::Some(10);
    let y: Option<String> = Option::None;
    
    println!("{:?}, {:?}, {:?}, {:?}, {:?}", 
             some_number, some_string, absent_number, x, y);
}

1.3 处理 Option 的基本方法

使用 match 处理

rust 复制代码
fn divide(numerator: f64, denominator: f64) -> Option<f64> {
    if denominator == 0.0 {
        None
    } else {
        Some(numerator / denominator)
    }
}

fn main() {
    let result = divide(10.0, 2.0);
    
    match result {
        Some(value) => println!("结果是: {}", value),
        None => println!("不能除以零"),
    }
    
    let invalid = divide(10.0, 0.0);
    
    match invalid {
        Some(value) => println!("结果是: {}", value),
        None => println!("不能除以零"),
    }
}

使用 if let 处理

rust 复制代码
fn main() {
    let some_value = Some(42);
    
    if let Some(x) = some_value {
        println!("值是: {}", x);
    } else {
        println!("没有值");
    }
    
    // 只关心 Some 的情况
    if let Some(x) = Some(100) {
        println!("有值: {}", x);
    }
}

1.4 Option 的常用方法

unwrap 系列

rust 复制代码
fn main() {
    let x = Some("value");
    let y: Option<&str> = None;
    
    // unwrap: 如果是 Some 返回值,如果是 None 则 panic
    println!("x.unwrap() = {}", x.unwrap()); // "value"
    // println!("y.unwrap() = {}", y.unwrap()); // 会 panic!
    
    // unwrap_or: 提供默认值
    println!("x.unwrap_or(\"default\") = {}", x.unwrap_or("default")); // "value"
    println!("y.unwrap_or(\"default\") = {}", y.unwrap_or("default")); // "default"
    
    // unwrap_or_else: 使用闭包计算默认值
    println!("y.unwrap_or_else(|| \"computed\") = {}", 
             y.unwrap_or_else(|| "computed")); // "computed"
    
    // expect: 类似 unwrap,但可以指定错误信息
    println!("x.expect(\"出错了\") = {}", x.expect("出错了")); // "value"
    // y.expect("值不存在"); // panic 并显示 "值不存在"
}

map 和 and_then

rust 复制代码
fn main() {
    let some_number = Some(10);
    
    // map: 对 Some 中的值进行转换
    let doubled = some_number.map(|x| x * 2);
    println!("doubled = {:?}", doubled); // Some(20)
    
    let none_number: Option<i32> = None;
    let still_none = none_number.map(|x| x * 2);
    println!("still_none = {:?}", still_none); // None
    
    // and_then: 链式操作,返回 Option
    fn square(x: i32) -> Option<i32> { Some(x * x) }
    fn none_if_negative(x: i32) -> Option<i32> {
        if x >= 0 { Some(x) } else { None }
    }
    
    let result = Some(4).and_then(square).and_then(|x| Some(x + 1));
    println!("result = {:?}", result); // Some(17)
    
    let chain_result = Some(-5).and_then(none_if_negative).and_then(square);
    println!("chain_result = {:?}", chain_result); // None
}

filter

rust 复制代码
fn main() {
    let some_number = Some(10);
    
    // filter: 根据条件过滤
    let filtered = some_number.filter(|&x| x > 5);
    println!("filtered = {:?}", filtered); // Some(10)
    
    let filtered_none = some_number.filter(|&x| x > 20);
    println!("filtered_none = {:?}", filtered_none); // None
    
    // 使用 None
    let none: Option<i32> = None;
    println!("none.filter(...) = {:?}", none.filter(|&x| x > 5)); // None
}

or 和 or_else

rust 复制代码
fn main() {
    let x = Some(2);
    let y = None;
    let z = Some(100);
    
    // or: 如果当前是 Some 则返回当前,否则返回另一个
    println!("x.or(z) = {:?}", x.or(z)); // Some(2)
    println!("y.or(z) = {:?}", y.or(z)); // Some(100)
    println!("y.or(y) = {:?}", y.or(y)); // None
    
    // or_else: 使用闭包
    println!("y.or_else(|| Some(999)) = {:?}", 
             y.or_else(|| Some(999))); // Some(999)
}

get_or_insert 系列

rust 复制代码
fn main() {
    let mut x = None;
    
    // get_or_insert: 如果是 None 则插入值
    let value = x.get_or_insert(5);
    println!("value = {}, x = {:?}", value, x); // 5, Some(5)
    *value += 1;
    println!("修改后 x = {:?}", x); // Some(6)
    
    // get_or_insert_with: 使用闭包
    let mut y: Option<String> = None;
    let s = y.get_or_insert_with(|| "default".to_string());
    println!("s = {}, y = {:?}", s, y); // "default", Some("default")
}

1.5 Option 的转换方法

rust 复制代码
fn main() {
    let some_option = Some(42);
    let none_option: Option<i32> = None;
    
    // ok_or: 将 Option 转换为 Result
    let result_ok = some_option.ok_or("没有值");
    println!("ok = {:?}", result_ok); // Ok(42)
    
    let result_err = none_option.ok_or("没有值");
    println!("err = {:?}", result_err); // Err("没有值")
    
    // ok_or_else: 使用闭包创建错误
    let result = none_option.ok_or_else(|| {
        println!("计算错误信息");
        "值不存在"
    });
    println!("result = {:?}", result); // Err("值不存在")
    
    // 转换为迭代器
    let iter = some_option.iter();
    for value in iter {
        println!("迭代器中的值: {}", value); // 42
    }
    
    // 检查是否包含特定值
    println!("some_option.contains(&42) = {}", some_option.contains(&42)); // true
    println!("some_option.contains(&100) = {}", some_option.contains(&100)); // false
}

2. Result 类型

2.1 什么是 Result?

Result<T, E> 是一个枚举,表示操作可能成功 (Ok) 或失败 (Err)。

rust 复制代码
enum Result<T, E> {
    Ok(T),   // 包含成功值 T
    Err(E),  // 包含错误值 E
}

2.2 创建 Result

rust 复制代码
use std::fs::File;
use std::io::Error;

fn main() {
    // 创建 Ok 和 Err
    let success: Result<i32, String> = Ok(42);
    let failure: Result<i32, String> = Err(String::from("出错了"));
    
    // 实际使用示例
    let file_result = File::open("test.txt");
    
    match file_result {
        Ok(file) => println!("文件打开成功: {:?}", file),
        Err(error) => println!("文件打开失败: {}", error),
    }
}

2.3 自定义错误类型

rust 复制代码
// 定义自己的错误类型
#[derive(Debug)]
enum MathError {
    DivisionByZero,
    NegativeSquareRoot,
    Overflow,
}

impl std::fmt::Display for MathError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            MathError::DivisionByZero => write!(f, "除数不能为零"),
            MathError::NegativeSquareRoot => write!(f, "不能对负数开平方根"),
            MathError::Overflow => write!(f, "计算溢出"),
        }
    }
}

impl std::error::Error for MathError {}

fn divide(a: f64, b: f64) -> Result<f64, MathError> {
    if b == 0.0 {
        Err(MathError::DivisionByZero)
    } else {
        Ok(a / b)
    }
}

fn main() {
    match divide(10.0, 0.0) {
        Ok(result) => println!("结果: {}", result),
        Err(error) => println!("错误: {}", error),
    }
}

2.4 Result 的常用方法

unwrap 系列

rust 复制代码
fn main() {
    let ok_result: Result<i32, &str> = Ok(42);
    let err_result: Result<i32, &str> = Err("出错了");
    
    // unwrap: 成功返回值,失败 panic
    println!("ok_result.unwrap() = {}", ok_result.unwrap()); // 42
    // println!("err_result.unwrap()"); // panic!
    
    // unwrap_or: 提供默认值
    println!("ok_result.unwrap_or(0) = {}", ok_result.unwrap_or(0)); // 42
    println!("err_result.unwrap_or(0) = {}", err_result.unwrap_or(0)); // 0
    
    // unwrap_or_else: 使用闭包计算默认值
    println!("err_result.unwrap_or_else(|e| {
        println!(\"错误是: {}\", e);
        999
    }) = {}", err_result.unwrap_or_else(|e| {
        println!("错误是: {}", e);
        999
    })); // 打印错误,返回 999
    
    // expect: 类似 unwrap,但可以指定错误信息
    println!("ok_result.expect(\"不应该出错\") = {}", 
             ok_result.expect("不应该出错")); // 42
    // err_result.expect("这里出错了"); // panic 并显示 "这里出错了: 出错了"
}

map 系列

rust 复制代码
fn main() {
    let ok: Result<i32, &str> = Ok(10);
    let err: Result<i32, &str> = Err("错误");
    
    // map: 转换成功值
    let doubled = ok.map(|x| x * 2);
    println!("doubled = {:?}", doubled); // Ok(20)
    
    let still_err = err.map(|x| x * 2);
    println!("still_err = {:?}", still_err); // Err("错误")
    
    // map_err: 转换错误值
    let mapped_err = err.map_err(|e| format!("严重错误: {}", e));
    println!("mapped_err = {:?}", mapped_err); // Err("严重错误: 错误")
    
    // map_or: 提供默认值并转换
    println!("ok.map_or(0, |x| x * 2) = {}", ok.map_or(0, |x| x * 2)); // 20
    println!("err.map_or(0, |x| x * 2) = {}", err.map_or(0, |x| x * 2)); // 0
    
    // map_or_else: 使用闭包
    let result = err.map_or_else(
        |e| format!("错误: {}", e).len(),  // 错误处理闭包
        |x| x * 2                         // 成功处理闭包
    );
    println!("map_or_else 结果 = {}", result); // 7 (中文字符长度)
}

and_then 和 or_else

rust 复制代码
fn main() {
    fn sqrt(x: f64) -> Result<f64, String> {
        if x >= 0.0 {
            Ok(x.sqrt())
        } else {
            Err(format!("不能计算 {} 的平方根", x))
        }
    }
    
    fn reciprocal(x: f64) -> Result<f64, String> {
        if x != 0.0 {
            Ok(1.0 / x)
        } else {
            Err("不能计算倒数".to_string())
        }
    }
    
    // and_then: 链式操作,每个步骤都可能失败
    let result = Ok(16.0)
        .and_then(sqrt)      // Ok(4.0)
        .and_then(reciprocal); // Ok(0.25)
    println!("result = {:?}", result); // Ok(0.25)
    
    let chain_err = Ok(-4.0).and_then(sqrt);
    println!("chain_err = {:?}", chain_err); // Err("不能计算 -4 的平方根")
    
    // or_else: 处理错误
    let recovered = Err("原始错误".to_string())
        .or_else(|_| Ok(42)); // 从错误中恢复
    println!("recovered = {:?}", recovered); // Ok(42)
}

错误传播:? 运算符

rust 复制代码
use std::fs::File;
use std::io::{self, Read};

// 传统错误处理
fn read_file_contents(path: &str) -> Result<String, io::Error> {
    let mut file = match File::open(path) {
        Ok(f) => f,
        Err(e) => return Err(e),
    };
    
    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Ok(_) => Ok(contents),
        Err(e) => Err(e),
    }
}

// 使用 ? 运算符简化
fn read_file_contents_simple(path: &str) -> Result<String, io::Error> {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

// 更简洁的写法
fn read_file_contents_even_simpler(path: &str) -> Result<String, io::Error> {
    let mut contents = String::new();
    File::open(path)?.read_to_string(&mut contents)?;
    Ok(contents)
}

fn main() {
    match read_file_contents_simple("test.txt") {
        Ok(contents) => println!("文件内容: {}", contents),
        Err(e) => println!("读取失败: {}", e),
    }
}

2.5 组合多个 Result

rust 复制代码
use std::error::Error;
use std::fmt;

#[derive(Debug)]
struct AppError {
    details: String,
}

impl fmt::Display for AppError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "应用错误: {}", self.details)
    }
}

impl Error for AppError {}

impl From<std::io::Error> for AppError {
    fn from(err: std::io::Error) -> Self {
        AppError {
            details: format!("IO错误: {}", err),
        }
    }
}

impl From<std::num::ParseIntError> for AppError {
    fn from(err: std::num::ParseIntError) -> Self {
        AppError {
            details: format!("解析错误: {}", err),
        }
    }
}

fn parse_number(s: &str) -> Result<i32, AppError> {
    Ok(s.parse()?)
}

fn read_and_parse() -> Result<i32, AppError> {
    // 模拟读取文件
    let content = std::fs::read_to_string("number.txt")?;
    let number = parse_number(&content)?;
    Ok(number)
}

fn main() {
    match read_and_parse() {
        Ok(n) => println!("解析到的数字: {}", n),
        Err(e) => println!("错误: {}", e),
    }
}

3. 组合处理 Option 和 Result

3.1 Option 和 Result 的相互转换

rust 复制代码
fn main() {
    // Option -> Result
    let some_value = Some(42);
    let none_value: Option<i32> = None;
    
    let result_ok = some_value.ok_or("没有值");
    println!("some -> result: {:?}", result_ok); // Ok(42)
    
    let result_err = none_value.ok_or("没有值");
    println!("none -> result: {:?}", result_err); // Err("没有值")
    
    // Result -> Option
    let ok_result: Result<i32, &str> = Ok(42);
    let err_result: Result<i32, &str> = Err("错误");
    
    println!("ok -> option: {:?}", ok_result.ok()); // Some(42)
    println!("err -> option: {:?}", err_result.ok()); // None
    
    println!("ok -> err option: {:?}", ok_result.err()); // None
    println!("err -> err option: {:?}", err_result.err()); // Some("错误")
}

3.2 transpose 方法

rust 复制代码
fn main() {
    // Option<Result<T, E>> -> Result<Option<T>, E>
    let option_result: Option<Result<i32, &str>> = Some(Ok(42));
    let result_option: Result<Option<i32>, &str> = option_result.transpose();
    println!("transpose 1: {:?}", result_option); // Ok(Some(42))
    
    let option_err: Option<Result<i32, &str>> = Some(Err("错误"));
    println!("transpose 2: {:?}", option_err.transpose()); // Err("错误")
    
    let none_option: Option<Result<i32, &str>> = None;
    println!("transpose 3: {:?}", none_option.transpose()); // Ok(None)
}

3.3 处理嵌套类型

rust 复制代码
fn process_nested(value: Option<Result<i32, String>>) -> Result<Option<String>, String> {
    value
        .transpose()?  // Option<Result> -> Result<Option>
        .map(|num| num.to_string())  // Option<i32> -> Option<String>
        .transpose()   // Result<Option<String>> 保持原样
}

fn main() {
    let nested1 = Some(Ok(42));
    let nested2 = Some(Err(String::from("错误")));
    let nested3: Option<Result<i32, String>> = None;
    
    println!("{:?}", process_nested(nested1)); // Ok(Some("42"))
    println!("{:?}", process_nested(nested2)); // Err("错误")
    println!("{:?}", process_nested(nested3)); // Ok(None)
}

4. 高级用法与模式

4.1 自定义错误类型和 thiserror 库

rust 复制代码
// 使用 thiserror 库简化错误定义
// Cargo.toml: thiserror = "1.0"

use thiserror::Error;

#[derive(Error, Debug)]
enum MyError {
    #[error("IO错误: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("解析错误: {0}")]
    Parse(#[from] std::num::ParseIntError),
    
    #[error("自定义错误: {0}")]
    Custom(String),
    
    #[error("数值 {0} 超出范围")]
    OutOfRange(i32),
}

fn process_data(path: &str) -> Result<i32, MyError> {
    let content = std::fs::read_to_string(path)?; // 自动转换为 MyError::Io
    let num: i32 = content.trim().parse()?;       // 自动转换为 MyError::Parse
    
    if num < 0 || num > 100 {
        return Err(MyError::OutOfRange(num));
    }
    
    if num == 42 {
        return Err(MyError::Custom("不能是 42".to_string()));
    }
    
    Ok(num * 2)
}

fn main() {
    match process_data("data.txt") {
        Ok(result) => println!("结果: {}", result),
        Err(e) => println!("错误: {}", e),
    }
}

4.2 anyhow 库用于应用程序错误处理

rust 复制代码
// 使用 anyhow 库简化错误处理
// Cargo.toml: anyhow = "1.0"

use anyhow::{Context, Result};

fn read_config() -> Result<String> {
    let path = "config.toml";
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("无法读取配置文件: {}", path))?;
    Ok(content)
}

fn parse_port(content: &str) -> Result<u16> {
    // 简单解析示例
    let port: u16 = content.trim().parse()
        .context("端口号解析失败")?;
    
    if port < 1024 {
        anyhow::bail!("端口号 {} 需要特权", port);
    }
    
    Ok(port)
}

fn main() -> Result<()> {
    let config = read_config()?;
    let port = parse_port(&config)?;
    println!("使用端口: {}", port);
    Ok(())
}

4.3 模式匹配的高级用法

rust 复制代码
fn process_result(result: Result<i32, String>) {
    match result {
        Ok(0) => println!("结果是零"),
        Ok(n @ 1..=10) => println!("结果在1-10之间: {}", n), // 绑定模式
        Ok(n) if n % 2 == 0 => println!("结果是偶数: {}", n), // 守卫条件
        Ok(n) => println!("结果是正数: {}", n),
        Err(ref e) if e.contains("超时") => println!("超时错误"),
        Err(e) => println!("其他错误: {}", e),
    }
}

fn extract_inner(result: Result<Option<i32>, String>) {
    if let Ok(Some(value @ 1..=100)) = result {
        println!("有效值: {}", value);
    }
}

fn main() {
    process_result(Ok(5));    // 结果在1-10之间: 5
    process_result(Ok(12));   // 结果是偶数: 12
    process_result(Err("连接超时".to_string())); // 超时错误
    
    extract_inner(Ok(Some(42))); // 有效值: 42
}

5. 实际应用示例

5.1 配置文件解析

rust 复制代码
use std::collections::HashMap;
use std::fs;

type Config = HashMap<String, String>;

fn parse_config(path: &str) -> Option<Config> {
    let content = fs::read_to_string(path).ok()?;
    
    let mut config = HashMap::new();
    
    for line in content.lines() {
        let line = line.trim();
        if line.is_empty() || line.starts_with('#') {
            continue;
        }
        
        let parts: Vec<&str> = line.splitn(2, '=').collect();
        if parts.len() == 2 {
            config.insert(
                parts[0].trim().to_string(),
                parts[1].trim().to_string(),
            );
        }
    }
    
    Some(config)
}

fn get_config_value(config: &Config, key: &str) -> Result<&str, String> {
    config
        .get(key)
        .map(|s| s.as_str())
        .ok_or_else(|| format!("配置项 '{}' 不存在", key))
}

fn main() {
    let config = parse_config("config.cfg").unwrap_or_default();
    
    match get_config_value(&config, "port") {
        Ok(port_str) => {
            match port_str.parse::<u16>() {
                Ok(port) if port > 0 => println!("端口号: {}", port),
                Ok(_) => eprintln!("端口号必须大于0"),
                Err(_) => eprintln!("端口号格式错误"),
            }
        }
        Err(e) => eprintln!("{}", e),
    }
}

5.2 数据库查询模拟

rust 复制代码
use std::error::Error;
use std::fmt;

#[derive(Debug, Clone)]
struct User {
    id: u32,
    name: String,
    email: Option<String>,
}

#[derive(Debug)]
enum DatabaseError {
    ConnectionFailed,
    UserNotFound(u32),
    InvalidQuery,
}

impl fmt::Display for DatabaseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            DatabaseError::ConnectionFailed => write!(f, "数据库连接失败"),
            DatabaseError::UserNotFound(id) => write!(f, "用户 {} 不存在", id),
            DatabaseError::InvalidQuery => write!(f, "查询语句无效"),
        }
    }
}

impl Error for DatabaseError {}

struct Database {
    connected: bool,
    users: Vec<User>,
}

impl Database {
    fn new() -> Self {
        Database {
            connected: false,
            users: vec![
                User { id: 1, name: "Alice".to_string(), email: Some("alice@example.com".to_string()) },
                User { id: 2, name: "Bob".to_string(), email: None },
                User { id: 3, name: "Charlie".to_string(), email: Some("charlie@example.com".to_string()) },
            ],
        }
    }
    
    fn connect(&mut self) -> Result<(), DatabaseError> {
        // 模拟连接有时成功有时失败
        self.connected = true;
        Ok(())
    }
    
    fn find_user_by_id(&self, id: u32) -> Result<Option<User>, DatabaseError> {
        if !self.connected {
            return Err(DatabaseError::ConnectionFailed);
        }
        
        let user = self.users.iter().find(|u| u.id == id).cloned();
        Ok(user)
    }
    
    fn get_user_email(&self, id: u32) -> Result<Option<String>, DatabaseError> {
        self.find_user_by_id(id)?
            .and_then(|user| user.email)
            .pipe(Ok)  // 包装回 Result
    }
}

// 辅助扩展方法
trait Pipe {
    fn pipe<F, T>(self, f: F) -> T
    where
        F: FnOnce(Self) -> T,
        Self: Sized;
}

impl<T> Pipe for T {
    fn pipe<F, R>(self, f: F) -> R
    where
        F: FnOnce(Self) -> R,
    {
        f(self)
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let mut db = Database::new();
    
    // 连接数据库
    db.connect()?;
    
    // 查询用户
    match db.find_user_by_id(2)? {
        Some(user) => {
            println!("找到用户: {}", user.name);
            if let Some(email) = user.email {
                println!("邮箱: {}", email);
            } else {
                println!("该用户没有邮箱");
            }
        }
        None => println!("用户不存在"),
    }
    
    // 直接获取邮箱
    match db.get_user_email(1)? {
        Some(email) => println!("邮箱: {}", email),
        None => println!("没有邮箱"),
    }
    
    // 处理不存在的用户
    match db.get_user_email(999) {
        Ok(None) => println!("用户 999 没有邮箱"),
        Ok(Some(email)) => println!("邮箱: {}", email),
        Err(e) => println!("查询失败: {}", e),
    }
    
    Ok(())
}

6. 最佳实践

6.1 何时使用 Option vs Result

  • 使用 Option:

    • 当值可能不存在是正常情况时
    • 查找操作(如 HashMap::get)
    • 可选配置项
  • 使用 Result:

    • 当操作可能失败且需要错误信息时
    • I/O 操作
    • 网络请求
    • 解析操作

6.2 错误处理策略

1. 传播错误 :使用 ? 运算符向上传播错误
2. 转换错误 :使用 map_err 或 From trait 转换错误类型
3. 恢复错误 :使用 or_else 或 unwrap_or 提供默认值
4. 组合错误:使用 anyhow 或 thiserror 库管理复杂错误类型

6.3 性能考虑

rust 复制代码
// 使用 Result 而不是 panic 进行错误处理
fn divide_result(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("除数不能为零".to_string())
    } else {
        Ok(a / b)
    }
}

// 避免过度使用 unwrap,使用模式匹配
fn safe_access(vec: &[i32], index: usize) -> Option<i32> {
    // 好:使用 get 返回 Option
    vec.get(index).copied()
    
    // 不好:可能 panic
    // Some(vec[index])
}

// 对于性能关键代码,考虑使用 unwrap
fn performance_critical(vec: &[i32]) -> i32 {
    // 只在确定不会失败时使用 unwrap
    vec.first().copied().unwrap_or(0)
}
相关推荐
王夏奇1 天前
Python库学习-标准库
学习
淺川之夏1 天前
abstract 类,里面引用@Autowired ,使用注入类的方法,报空指针异常
java·开发语言
独自破碎E1 天前
Spring Boot支持哪些嵌入Web容器?
前端·spring boot·后端
计算衎1 天前
Window下关于robocopy命令的讲解以及和Copy命令的区别
开发语言·bat
疯狂成瘾者1 天前
后端Spring Boot 核心知识点
java·spring boot·后端
小此方1 天前
Re: 从零开始的C++ 入門(十)类和对象·最终篇下:类型转换、static成员、友元、匿名对象、内部类、拷贝编译优化
开发语言·c++·底层
南桥几晴秋1 天前
QT按钮控件
开发语言·qt
xj7573065331 天前
《python web开发 测试驱动方法》
开发语言·前端·python
wenxin-1 天前
NS3学习-Packet数据包结构
网络·学习·ns3·ns3内核