MST
星途 面试题库

面试题:Rust运行时错误处理之Result类型深度运用

编写一个Rust函数,该函数接受一个文件路径作为参数,尝试读取文件内容,将文件内容解析为JSON格式的数据(假设数据结构为 `serde_json::Value`)。如果文件不存在,返回一个自定义的运行时错误;如果文件内容解析失败,也返回相应的运行时错误。请详细说明 `Result` 类型在这个过程中是如何处理运行时错误的,以及如何正确地传播和处理这些错误。
30.1万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
use std::fs::File;
use std::io::{self, Read};
use serde_json::{self, Value};

// 自定义运行时错误
#[derive(Debug)]
enum MyError {
    FileNotFound,
    JsonParseError(serde_json::Error),
}

impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            MyError::FileNotFound => write!(f, "文件不存在"),
            MyError::JsonParseError(e) => write!(f, "JSON解析错误: {}", e),
        }
    }
}

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

fn read_json_file(file_path: &str) -> Result<Value, MyError> {
    let mut file = match File::open(file_path) {
        Ok(file) => file,
        Err(_) => return Err(MyError::FileNotFound),
    };

    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Ok(_) => (),
        Err(e) => return Err(MyError::JsonParseError(serde_json::Error::custom(format!("读取文件错误: {}", e)))),
    };

    match serde_json::from_str(&contents) {
        Ok(value) => Ok(value),
        Err(e) => Err(MyError::JsonParseError(e)),
    }
}

Result 类型处理运行时错误的说明

  1. 错误传播
    • read_json_file 函数中,File::open 可能会因为文件不存在等I/O错误而失败。这里使用 match 语句处理 Result,如果 File::open 返回 Err,直接返回 Err(MyError::FileNotFound),将错误传播给调用者。
    • file.read_to_string 也可能失败,同样使用 match 处理 Result,如果失败则构造一个自定义的 serde_json::Error 并返回 Err
    • serde_json::from_str 用于将字符串解析为 Value,如果解析失败,返回 Err(MyError::JsonParseError(e)),其中 eserde_json::Error
  2. 错误处理
    • 调用者在调用 read_json_file 函数时,会得到一个 Result<Value, MyError>。调用者可以使用 match 语句处理这个 Result
fn main() {
    let result = read_json_file("path/to/your/file.json");
    match result {
        Ok(value) => println!("解析成功: {:?}", value),
        Err(e) => println!("错误: {}", e),
    }
}
- 或者使用 `unwrap` 或 `expect` 等方法,`unwrap` 在遇到 `Err` 时会直接 `panic!`,`expect` 可以提供自定义的 `panic!` 信息。不过在实际生产代码中,通常更建议使用 `match` 或 `if let` 来优雅地处理错误,而不是直接 `panic!`。例如:
fn main() {
    let value = read_json_file("path/to/your/file.json").expect("读取并解析JSON文件失败");
    println!("解析成功: {:?}", value);
}

这种方式适用于在开发过程中快速定位错误,或者在确保不会出现错误的情况下使用。但在生产环境中,建议更稳健的错误处理方式。