简体   繁体   English

如何为实现特定特征的所有类型批量实现反序列化?

[英]How can I mass implement Deserialize for all types that implement a specific trait?

I am deserializing a YAML config file with Serde.我正在使用 Serde 反序列化 YAML 配置文件。 For most structs I deserialize into, things are quite simple — there's a one-to-one relationship between the fields of the structs and the properties in my YAML file.对于我反序列化的大多数结构,事情非常简单——结构的字段和我的 YAML 文件中的属性之间存在一对一的关系。

In a few cases, things are a bit more complicated.在少数情况下,事情会更复杂一些。 For these, the properties in the YAML file are better viewed as parameters to the constructor.对于这些,最好将 YAML 文件中的属性视为构造函数的参数。 The actual struct will have different fields, calculated from those.实际的结构将有不同的字段,根据这些字段计算。

For these cases, I have written separate config structs that I deserialize into.对于这些情况,我编写了反序列化的单独配置结构。 For simplicity, consider this silly example:为简单起见,考虑这个愚蠢的例子:

struct Message {
    text: String,
}

impl Message {
    fn from_config(config: MessageConfig) -> Message {
        Message {
            text: format!("{} {}", config.first_half, config.second_half),
        }
    }
}

#[derive(Deserialize)]
struct MessageConfig {
    first_half: String,
    second_half: String,
}

To have Serde do the conversion from MessageConfig to Message for me, I implemented Deserialize for Message :为了让 Serde 为我完成从MessageConfigMessage的转换,我为Message实现了Deserialize

impl<'de> Deserialize<'de> for Message {
    fn deserialize<D>(deserializer: D) -> Result<Message, D::Error>
    where
        D: Deserializer<'de>,
    {
        MessageConfig::deserialize(deserializer).map(|config| Message::from_config(config))
    }
}

This works, but there would be a lot of copy pasting of the deserialization code involved if I were to do this for every struct, so I figured I should make a trait out of it:这是可行的,但是如果我要为每个结构执行此操作,则会涉及大量反序列化代码的复制粘贴,因此我想我应该从中创建一个特征:

use serde::{Deserialize, Deserializer};
use serde_json;
#[macro_use]
extern crate serde_derive;

trait Configurable {
    type Config;
    fn from_config(config: Self::Config) -> Self;
}

impl<'de, T, C> Deserialize<'de> for T
where
    T: Configurable<Config = C>,
    C: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<T, D::Error>
    where
        D: Deserializer<'de>,
    {
        Self::Config::deserialize(deserializer).map(|config| Self::from_config(config))
    }
}

struct Message {
    text: String,
}

impl<'de> Configurable for Message {
    type Config = MessageConfig;

    fn from_config(config: MessageConfig) -> Message {
        Message {
            text: format!("{} {}", config.first_half, config.second_half),
        }
    }
}

#[derive(Deserialize)]
struct MessageConfig {
    first_half: String,
    second_half: String,
}

However, the compiler is not happy about this:但是,编译器对此并不满意:

error[E0119]: conflicting implementations of trait `_IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'_>` for type `std::boxed::Box<_>`:
  --> src/lib.rs:11:1
   |
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | |     T: Configurable<Config = C>,
14 | |     C: Deserialize<'de>,
...  |
21 | |     }
22 | | }
   | |_^
   |
   = note: conflicting implementation in crate `serde`:
           - impl<'de, T> _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de> for std::boxed::Box<T>
             where T: _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de>;
   = note: downstream crates may implement trait `Configurable` for type `std::boxed::Box<_>`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`)
  --> src/lib.rs:11:1
   |
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | |     T: Configurable<Config = C>,
14 | |     C: Deserialize<'de>,
...  |
21 | |     }
22 | | }
   | |_^ type parameter `T` must be used as the type parameter for some local type
   |
   = note: only traits defined in the current crate can be implemented for a type parameter

The error messages make little sense to me.错误消息对我来说毫无意义。 What does Box have to do with anything? Box和什么有什么关系? And is it somehow possible to make this trait work?是否有可能使这种特性发挥作用?

I am not sure if there's a way to define such a broad trait without causing conflicting implementations.我不确定是否有一种方法可以定义如此广泛的特征而不会导致实现冲突。 What you could do is use a macro to avoid repetition:您可以做的是使用宏来避免重复:

use serde::{Deserialize, Deserializer};
use serde_json;

use serde_json::Error;

#[macro_use]
extern crate serde_derive;

struct Message {
    text: String,
}

#[derive(Deserialize)]
struct MessageConfig {
    first_half: String,
    second_half: String,
}

impl Message {
    fn from_config(config: MessageConfig) -> Message {
        Message {
            text: format!("{} {}", config.first_half, config.second_half),
        }
    }
}

macro_rules! derive_configurable_serializer {
    ( $t:ident, $c:ident ) => {
        impl<'de> Deserialize<'de> for $t {
            fn deserialize<D>(deserializer: D) -> Result<$t, D::Error>
            where
                D: Deserializer<'de>,
            {
                $c::deserialize(deserializer).map(|config| $t::from_config(config))
            }
        }
    };
}

derive_configurable_serializer!(Message, MessageConfig);

fn main() -> Result<(), Error> {
    let data = r#"{ "first_half": "John", "second_half": "Doe" }"#;

    let p: Message = serde_json::from_str(data)?;

    println!("Hello, {}!", p.text);

    Ok(())
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何为实现特征的所有类型实现From特质,但对某些类型使用特定的实现? - How can I implement the From trait for all types implementing a trait but use a specific implementation for certain types? 如果两个特征都是为引用实现的,那么如何为实现特征A的所有类型实现特征B? - How can I implement trait B for all types that implement trait A if both traits are implemented for references? 无法为实现我拥有的特征的所有类型实现我不拥有的特征 - Can't implement a trait I don't own for all types that implement a trait I do own 如何获得在Rust中实现特定特征的类型列表? - How can I get a list of types that implement a particular trait in Rust? 为实现 trait 的所有类型实现 trait - Implement a trait for all types implementing a trait 如何为实现该特征的现有类型的枚举实现范围内的特征? - How can I implement a trait in scope for an enum of existing types for which the trait is implemented? 为实现特定类型的 trait 的泛型类型实现 trait - Implement a trait for generic types that implement a trait for a specific type 如何在 num 库中的 BigInt 结构上实现反序列化特征? - How can I implement the Deserialize trait on the BigInt struct from the num library? 我可以有一个泛型函数来接受所有未实现特征的类型吗? - Can I have a generic function that accepts all types that do not implement a trait? 如何为特征实现“默认迭代器”? - How can I implement a “default iterator” for a trait?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM