< 返回版块

xzzy 发表于 2023-02-05 21:06

示例代码:

use std::fmt;

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

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

impl fmt::Display for AppError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match &self.kind as &str {
            "404" => write!(
                f,
                "程序出错:{{错误类型: {}, 错误原因: {}}}",
                self.kind, self.message
            ),
            _ => write!(f, "Sorry, something is wrong! Please Try Again!"),
        }
    }
}

fn produce_error() -> Result<(), AppError> {
    Err(AppError {
        kind: String::from("404"),
        message: String::from("Page not found"),
    })
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    match produce_error() {
        Err(err) => println!("{}", err),
        _ => println!("No error"),
    }
    Ok(())
}

运行后正常调用fmt方法格式化输出:

程序出错:{错误类型: 404, 错误原因: Page not found}

使用?操作符,将main函数修改为:

fn main() -> Result<(), Box<dyn std::error::Error>> {
    produce_error()?;
    Ok(())
}

再次运行后输出:

Error: AppError { kind: "404", message: "Page not found" }

无法调用fmt方法格式化输出!

playground

求解

评论区

写评论
苦瓜小仔 2023-02-06 09:13

注意 String 的 Debug 来自 str

这也意味着转义字符被处理为 \x 来显示,对于 "程序出错:\n{{错误类型: {}, 错误原因: {}}}"

方法一:
Error: "程序出错:\n{错误类型: 404, 错误原因: Page not found}"

方法二:
Error: 程序出错:
{错误类型: 404, 错误原因: Page not found}

方法三:
Error: 程序出错:
{错误类型: 404, 错误原因: Page not found}

Location:
    src/main.rs:37:5

是的,错误处理库都是在自定义的 Error 类型的 Debug 实现上使用其来源的 Display 实现。

不要第三方库的最简单的做法是手动实现 Debug

impl fmt::Debug for AppError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

打印:
Error: 程序出错:
{错误类型: 404, 错误原因: Page not found}

如果只是写例子,方法一和这种方法当然没问题,但用专门的错误处理库会更省心,尤其是你想加 Context。

anyhow

use anyhow::Context;
fn main() -> anyhow::Result<()> {
    produce_error().with_context(|| "如果我想加点上下文相关的信息来丰富错误消息呢?")?;

Error: 如果我想加点上下文相关的信息来丰富错误消息呢?

Caused by:
    程序出错:
    {错误类型: 404, 错误原因: Page not found}

eyre

use eyre::WrapErr;
fn main() -> eyre::Result<()> {
    produce_error().wrap_err("如果我想加点上下文相关的信息来丰富错误消息呢?")?;

Error: 如果我想加点上下文相关的信息来丰富错误消息呢?

Caused by:
    程序出错:{错误类型: 404, 错误原因: Page not found}

Location:
    src/main.rs:38:21
作者 xzzy 2023-02-05 22:32

好的,我去了解了解!

--
👇
苦瓜小仔: 方法一: 直接基于 Display ,注意 String 的 Debug 来自 str,所以两边有引号

produce_error().map_err(|e| e.to_string())?;
// Error: "程序出错:{错误类型: 404, 错误原因: Page not found}"

方法二:第三方库, anyhow(打印错误时做了内部自定义处理,注意两边没有引号 )

fn main() -> anyhow::Result<()> {
// Error: 程序出错:{错误类型: 404, 错误原因: Page not found}

方法三:第三方库,eyre (专注于良好的错误报告,注意报告了错误发生的源码位置)

fn main() -> eyre::Result<()> {

// Error: 程序出错:{错误类型: 404, 错误原因: Page not found}
//
// Location:
//     src/main.rs:37:5
苦瓜小仔 2023-02-05 22:22

方法一: 直接基于 Display ,注意 String 的 Debug 来自 str,所以两边有引号

produce_error().map_err(|e| e.to_string())?;
// Error: "程序出错:{错误类型: 404, 错误原因: Page not found}"

方法二:第三方库, anyhow(打印错误时做了内部自定义处理,注意两边没有引号 )

fn main() -> anyhow::Result<()> {
// Error: 程序出错:{错误类型: 404, 错误原因: Page not found}

方法三:第三方库,eyre (专注于良好的错误报告,注意报告了错误发生的源码位置)

fn main() -> eyre::Result<()> {

// Error: 程序出错:{错误类型: 404, 错误原因: Page not found}
//
// Location:
//     src/main.rs:37:5
作者 xzzy 2023-02-05 22:08

懂了,非常感谢您的解答!那么有什么办法可以解决这个问题优雅地打印错误信息吗?

--
👇
jiacai2050: https://doc.rust-lang.org/reference/crates-and-source-files.html#main-functions

这里有说,main 方法返回 Result 时,要求 Err 实现 Debug,证明它会用 Debug 实现来打印,这个你是改不了的。

jiacai2050 2023-02-05 21:50

https://doc.rust-lang.org/reference/crates-and-source-files.html#main-functions

这里有说,main 方法返回 Result 时,要求 Err 实现 Debug,证明它会用 Debug 实现来打印,这个你是改不了的。

1 共 5 条评论, 1 页