我正在为serde编写一个自定义序列化器. 为此,我还需要一个自定义错误类型. Serde要求我为此实现serde::ser::Error. serde::ser::Error反过来又要求我实现一个custom()方法,其中参数只受std::fmt::Display trait绑定的限制. 所以我想到了这个:

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))
    }
}

然而,我不能推导出Debug,这是std::error::Error所必需的,而std::error::Error又是serde::ser::Error所必需的,因为Box<dyn Display>并不实现Debug. 我不能为它实现Debug,因为Box和trait Debug本身都不在我的crate中. 我也不能在custom()中为T添加适当的约束,因为这会 destruct trait的契约.

我怎么才能解决这个问题?

推荐答案

你可以使用一个小把戏,基于两个事实:

因此,只要你有T: Display,你就可以得到Box<dyn Error>,而不是Box<dyn Display>,就像这样(playground):

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 Error就是Debug.

Rust相关问答推荐

PyReadonlyArray2到Vec T<>

Rust中的相互递归特性与默认实现

修改切片/引用数组

如何获取Serde struct 的默认实例

在跨平台应用程序中使用std::OS::Linux和std::OS::Windows

使用极点数据帧时,找不到枚举结果的方法lazy()

在rust sqlx中使用ilike和push bind

为什么`AlternateScreen`在读取输入键时需要按Enter键?

如何将实现多个特征的 struct 传递给接受这些特征为&;mut?

Rust将String上的迭代器转换为&;[&;str]

Const 上下文:从 init 函数创建具有 const 通用长度的数组

如何使用tracing-subscriberRust crate 构建多编写者、全局过滤订阅者

为什么我可以使用 &mut (**ref) 创建两个实时 &mut 到同一个变量?

为什么是&mut发送?线程如何在安全的 Rust 中捕获 &mut?

仅当函数写为闭包时才会出现生命周期错误

在运行时在 Rust 中加载字体

如何获取函数中borrow 的切片的第一部分?

如何在 use_effect_with_deps 中设置监听器内的状态?

如何在 Rust 中创建最后一个元素是可变长度数组的 struct ?

Rust 内联 asm 中的向量寄存器:不能将 `Simd` 类型的值用于内联汇编