如何实现 serde::ser::Error 的调试

How to implement Debug for serde::ser::Error

提问人:Richard Neumann 提问时间:11/8/2023 更新时间:11/8/2023 访问量:44

问:

我正在为 serde 编写一个自定义序列化程序。 为此,我还需要一个自定义错误类型。 Serde 要求我为此实现。 反过来,要求我实现一个方法,其中参数仅受特征边界的限制。 所以我想出了这个:serde::ser::Errorserde::ser::Errorcustom()std::fmt::Display

use std::fmt::{Debug, Display, Formatter};

#[derive(Debug)]
pub enum Error {
    Custom(Box<dyn Display>),
    CannotSerializeMap,
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Custom(error) => Display::fmt(error, f),
            Self::CannotSerializeMap => write!(f, "cannot serialize map"),
        }
    }
}

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

impl serde::ser::Error for Error {
    fn custom<T>(msg: T) -> Self
    where
        T: Display,
    {
        Self::Custom(Box::new(msg))
    }
}

但是,我不能推导出 ,这是必需的,而 又是必需的,因为不实现 。 我无法实现它,因为特征本身都不在我的板条箱中。 我也无法为 in 添加适当的约束,因为它会破坏特征的契约。Debugstd::error::Errorserde::ser::ErrorBox<dyn Display>DebugDebugBoxDebugTcustom()

我该如何解决这个问题?

评论

0赞 cafce25 11/8/2023
你可以实现它,而不是派生它!Debug for Error

答:

2赞 Cerberus 11/8/2023 #1

你可以根据两个事实使用一个小技巧:

  • 实现的所有内容也实现 ToString(通过将值格式化为空字符串)。DisplayDisplay
  • 可以使用 From 实现创建 from。Box<dyn Error>String

因此,每当你有一些 ,你可以得到一个 ,而不是像这样(playground):T: DisplayBox<dyn Display>Box<dyn Error>

use std::fmt::{Debug, Display, Formatter};

#[derive(Debug)]
pub enum Error {
    Custom(Box<dyn std::error::Error>),
    CannotSerializeMap,
}

impl serde::ser::Error for Error {
    fn custom<T>(msg: T) -> Self
    where
        T: Display,
    {
        Self::Custom(msg.to_string().into())
    }
}

然后开箱即用(双关语),因为是.#[derive(Debug)]dyn ErrorDebug

评论

1赞 Chayim Friedman 11/9/2023
在这一点上,为什么不直接存储呢?它既便宜又允许更多功能。当然,您可能希望使用原始类型,但无论如何,这个技巧都不起作用。String