在 Rust 中使用 Box 处理错误

Beginner

This tutorial is from open-source community. Access the source code

简介

在本实验中,代码展示了如何使用 Box 类型通过包装来保留原始错误,从而实现动态错误处理,并且 Std 库的 From 特性有助于将任何实现 Error 特性的类型转换为特性对象 Box<Error>。它包含一个使用 Box 和自定义错误类型进行错误转换和处理的示例。

注意:如果实验未指定文件名,你可以使用任何你想要的文件名。例如,你可以使用 main.rs,并通过 rustc main.rs &&./main 进行编译和运行。

Box 包装错误

一种在保留原始错误的同时编写简单代码的方法是使用 Box 对它们进行包装。缺点是底层错误类型仅在运行时可知,而不是在编译时静态确定。

标准库通过让 Box 实现从任何实现 Error 特性的类型到特性对象 Box<Error> 的转换(通过 From),来帮助我们对错误进行装箱。

use std::error;
use std::fmt;

// 将别名更改为 `Box<error::Error>`。
type Result<T> = std::result::Result<T, Box<dyn error::Error>>;

#[derive(Debug, Clone)]
struct EmptyVec;

impl fmt::Display for EmptyVec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "invalid first item to double")
    }
}

impl error::Error for EmptyVec {}

fn double_first(vec: Vec<&str>) -> Result<i32> {
    vec.first()
     .ok_or_else(|| EmptyVec.into()) // 转换为 Box
     .and_then(|s| {
            s.parse::<i32>()
             .map_err(|e| e.into()) // 转换为 Box
             .map(|i| 2 * i)
        })
}

fn print(result: Result<i32>) {
    match result {
        Ok(n) => println!("The first doubled is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    let numbers = vec!["42", "93", "18"];
    let empty = vec![];
    let strings = vec!["tofu", "93", "18"];

    print(double_first(numbers));
    print(double_first(empty));
    print(double_first(strings));
}

总结

恭喜你!你已经完成了“用 Box 包装错误”实验。你可以在 LabEx 中练习更多实验来提升你的技能。