MST

星途 面试题库

面试题:Rust自定义错误类型与异步编程结合及错误传播优化

假设你正在编写一个异步Rust程序,其中有多个异步函数相互调用。需要定义一个自定义错误类型`AppError`,它继承自`std::error::Error`。在异步函数链中,要合理地传播`AppError`,并且在顶层函数捕获错误时,能够将错误信息以结构化的形式(例如JSON格式)记录到日志中。同时,考虑如何优化错误传播过程,减少不必要的装箱操作。请给出关键代码片段及简要说明。
42.3万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
use std::error::Error;
use serde::{Serialize, Deserialize};
use tracing::{error, info};

// 定义自定义错误类型
#[derive(Debug, Serialize, Deserialize)]
struct AppError {
    message: String,
}

impl Error for AppError {}

impl std::fmt::Display for AppError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.message)
    }
}

// 示例异步函数,会返回AppError
async fn inner_function() -> Result<(), AppError> {
    // 模拟一些可能出错的操作
    Err(AppError { message: "Inner function error".to_string() })
}

// 调用inner_function并传播错误
async fn middle_function() -> Result<(), AppError> {
    inner_function().await?;
    Ok(())
}

// 顶层函数,捕获错误并记录日志
async fn top_level_function() {
    match middle_function().await {
        Ok(_) => info!("All operations completed successfully"),
        Err(e) => {
            let json_error = serde_json::to_string(&e).unwrap_or_else(|_| "Serialization error".to_string());
            error!("Error occurred: {}", json_error);
        }
    }
}

代码说明

  1. 定义自定义错误类型 AppError:实现了 Error 特质以及 Display 特质,并且为了方便转为JSON格式,实现了 SerializeDeserialize 特质。
  2. inner_function:模拟一个可能会返回 AppError 的异步函数。
  3. middle_function:调用 inner_function 并使用 ? 操作符来传播错误。
  4. top_level_function:调用 middle_function 并在 match 块中捕获错误。将错误转换为JSON格式并记录到日志中。

优化措施

  • 在定义 AppError 时,避免使用动态分配(如 Box<dyn Error>),这样可以减少不必要的装箱操作。
  • 使用 ? 操作符在异步函数链中简洁地传播错误,使得错误处理代码更加清晰,也有助于编译器进行优化。