Serialization 使用serde对yaml或json进行反序列化时,如何分解枚举?

Serialization 使用serde对yaml或json进行反序列化时,如何分解枚举?,serialization,rust,yaml,deserialization,serde,Serialization,Rust,Yaml,Deserialization,Serde,我有一段serde代码,它能满足我的需要,但我不喜欢它的工作方式。我正在寻求帮助,以找出如何改进它 应解析为struct Connector 我想我可以使用枚举表示来处理这个问题,但是,它会产生不希望的副作用-默认情况下,遵循yaml: - id: Foo source: Bar type: Connector - id: Foo source: Bar type: Generator 将被解析为: [Connector(Connector{...}), Generator(

我有一段
serde
代码,它能满足我的需要,但我不喜欢它的工作方式。我正在寻求帮助,以找出如何改进它

应解析为
struct Connector

我想我可以使用枚举表示来处理这个问题,但是,它会产生不希望的副作用-默认情况下,遵循yaml:

- id: Foo
  source: Bar
  type: Connector
- id: Foo
  source: Bar
  type: Generator
将被解析为:

[Connector(Connector{...}), Generator(Generator{...})]
因此,我的结构被包装在枚举变量中。为了“展开它”,我想我可以从迭代器实现

#[serde(from=“FromType”)]
-我认为它的工作方式是强制将枚举变量直接转换为所需的结构,无需额外迭代和代码重复。然而,我没有实现它-

当我试图从
属性添加

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
enum AllModels {
  Gene(Generator),
  Connector(Connector),
}
编译器会对我大喊大叫

 ❯ cargo r
   Compiling serdeissue v0.1.0 (/sandbox/serdeissue)
error[E0277]: the trait bound `Box<dyn Model>: From<AllModels>` is not satisfied
  --> src/main.rs:21:24
   |
21 | #[derive(Debug, Clone, Serialize, Deserialize)]
   |                        ^^^^^^^^^ the trait `From<AllModels>` is not implemented for `Box<dyn Model>`
   |
   = help: the following implementations were found:
             <Box<(dyn StdError + 'a)> as From<E>>
             <Box<(dyn StdError + 'static)> as From<&str>>
             <Box<(dyn StdError + 'static)> as From<Cow<'a, str>>>
             <Box<(dyn StdError + 'static)> as From<std::string::String>>
           and 22 others
   = note: required because of the requirements on the impl of `Into<Box<dyn Model>>` for `AllModels`
   = note: required by `into`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `dyn Model: Serialize` is not satisfied
   --> src/main.rs:21:24
    |
21  | #[derive(Debug, Clone, Serialize, Deserialize)]
    |                        ^^^^^^^^^ the trait `Serialize` is not implemented for `dyn Model`
    |
   ::: /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/ser/mod.rs:247:18
    |
247 |     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    |                  - required by this bound in `serialize`
    |
    = note: required because of the requirements on the impl of `Serialize` for `Box<dyn Model>`
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `dyn Model: Deserialize<'_>` is not satisfied
   --> src/main.rs:21:35
    |
21  | #[derive(Debug, Clone, Serialize, Deserialize)]
    |                                   ^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `dyn Model`
    |
   ::: /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/de/mod.rs:539:12
    |
539 |         D: Deserializer<'de>;
    |            ----------------- required by this bound in `_::_serde::Deserialize::deserialize`
    |
    = note: required because of the requirements on the impl of `Deserialize<'_>` for `Box<dyn Model>`
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `AllModels: From<Box<dyn Model>>` is not satisfied
   --> src/main.rs:21:35
    |
21  | #[derive(Debug, Clone, Serialize, Deserialize)]
    |                                   ^^^^^^^^^^^ the trait `From<Box<dyn Model>>` is not implemented for `AllModels`
    |
   ::: /home/marcin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:372:1
    |
372 | pub trait From<T>: Sized {
    | ------------------------ required by this bound in `From`
    |
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
我正在寻找的功能似乎正等待在此处实现:

还有一个问题建议手动反序列化器实现。游乐场代码表明,这可能有助于解决我的问题#2“额外迭代”,但代码实现中仍有一些重复,因此我仍在寻找更好的答案



编辑:我也在考虑,不知道什么是评估我是否需要其中一个的正确方法。

我找到了一个让我满意的解决方案:

  • 光滑的
  • 没有代码重复
  • 没有动态调度,没有额外的迭代
  • 使用
    enum
    serde(tag=“…”)
    • type
      字段在json/yaml中可能会出现顺序错误(不必是第一个)
    • 类型
      字段在序列化回json/yaml时包含在内
诀窍是使用

使用serde::{序列化,反序列化};
使用enum_dispatch::enum_dispatch;
#[派生(调试、克隆、序列化、反序列化)]
结构生成器{
source_id:String,
id:String,
}
#[派生(调试、克隆、序列化、反序列化)]
结构门{
source_id:String,
id:String,
}
#[枚举调度]
性状模型{fn时间推进(self,a:i32,b:i32)->i32;}
发电机{fn时间推进(self,a:i32,b:i32)->i32{a+b}的impl模型
门{fn时间推进(self,a:i32,b:i32)->i32{a+b}的impl模型
#[枚举调度(模型)]
#[派生(调试、克隆、序列化、反序列化)]
#[serde(tag=“type”)]
枚举模型类型{
发电机(发电机),
门(门),,
}
fn main(){
设s=r#”
-来源_id:“发电机-01”
id:“连接器-01”
类型:“发电机”
-来源编号:“geneiator-01”
类型:“浇口”
id:“连接器-01”
"#;
让数据:Vec=serde_yaml::from_str(s).unwrap();
println!(“{:?}”,serde_yaml::to_string(&data));
对于数据中的d{
println!(“{:?}”,d.time_-advance(4,2));
}
}
输出:

>货物运输
编译enum_unpack v0.1.0(…/enum_unpack)
在0.66秒内完成开发[未优化+调试信息]目标
正在运行“目标/调试/枚举”解包`
正常(“--\n-类型:生成器\n源\u id:生成器-01\n id:连接器-01\n-类型:门\n源\u id:生成器-01\n id:连接器-01\n”)
6.
6.
[Connector{...}, Generator{...}]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
enum AllModels {
  Gene(Generator),
  Connector(Connector),
}
 ❯ cargo r
   Compiling serdeissue v0.1.0 (/sandbox/serdeissue)
error[E0277]: the trait bound `Box<dyn Model>: From<AllModels>` is not satisfied
  --> src/main.rs:21:24
   |
21 | #[derive(Debug, Clone, Serialize, Deserialize)]
   |                        ^^^^^^^^^ the trait `From<AllModels>` is not implemented for `Box<dyn Model>`
   |
   = help: the following implementations were found:
             <Box<(dyn StdError + 'a)> as From<E>>
             <Box<(dyn StdError + 'static)> as From<&str>>
             <Box<(dyn StdError + 'static)> as From<Cow<'a, str>>>
             <Box<(dyn StdError + 'static)> as From<std::string::String>>
           and 22 others
   = note: required because of the requirements on the impl of `Into<Box<dyn Model>>` for `AllModels`
   = note: required by `into`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `dyn Model: Serialize` is not satisfied
   --> src/main.rs:21:24
    |
21  | #[derive(Debug, Clone, Serialize, Deserialize)]
    |                        ^^^^^^^^^ the trait `Serialize` is not implemented for `dyn Model`
    |
   ::: /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/ser/mod.rs:247:18
    |
247 |     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    |                  - required by this bound in `serialize`
    |
    = note: required because of the requirements on the impl of `Serialize` for `Box<dyn Model>`
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `dyn Model: Deserialize<'_>` is not satisfied
   --> src/main.rs:21:35
    |
21  | #[derive(Debug, Clone, Serialize, Deserialize)]
    |                                   ^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `dyn Model`
    |
   ::: /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/de/mod.rs:539:12
    |
539 |         D: Deserializer<'de>;
    |            ----------------- required by this bound in `_::_serde::Deserialize::deserialize`
    |
    = note: required because of the requirements on the impl of `Deserialize<'_>` for `Box<dyn Model>`
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `AllModels: From<Box<dyn Model>>` is not satisfied
   --> src/main.rs:21:35
    |
21  | #[derive(Debug, Clone, Serialize, Deserialize)]
    |                                   ^^^^^^^^^^^ the trait `From<Box<dyn Model>>` is not implemented for `AllModels`
    |
   ::: /home/marcin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:372:1
    |
372 | pub trait From<T>: Sized {
    | ------------------------ required by this bound in `From`
    |
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
impl From<AllModels> for Box<dyn Model> {
    fn from(am: AllModels) -> Self {
        Box::new(Generator{id:String::from("arst"),source_id:String::from("arst")})
    }
}
impl Serialize for dyn Model {
    fn serialize(&self) -> Self {
        Box::new(Generator{id:String::from("arst"),source_id:String::from("arst")})
    }
}

impl Deserialize<'_> for dyn Model {}
impl From<Box<dyn Model>> for AllModels {
    fn from(dm: Box<dyn Model>) -> Self {
        AllModels::Gene(Generator{id:String::from("arst"),source_id:String::from("arst")})
    }
}
 ❯ cargo r
   Compiling serdeissue v0.1.0 (/sandbox/serdeissue)
error[E0277]: the size for values of type `(dyn Model + 'static)` cannot be known at compilation time
   --> src/main.rs:75:6
    |
75  | impl Deserialize<'_> for dyn Model {}
    |      ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
   ::: /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/de/mod.rs:530:29
    |
530 | pub trait Deserialize<'de>: Sized {
    |                             ----- required by this bound in `Deserialize`
    |
    = help: the trait `Sized` is not implemented for `(dyn Model + 'static)`
use erased_serde::{Deserializer,  Serializer, serialize_trait_object};
use serde::{Serialize, Deserialize};


#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Generator {
  id: String,
  source: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Connector {
  id: String,
  source: String,
}

trait Model: std::fmt::Debug + erased_serde::Serialize {}
erased_serde::serialize_trait_object!(Model);
impl Model for Generator {}
impl Model for Connector {}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", into = "Box<dyn Model>", from = "Box<dyn Model>")]
enum AllModels {
  Generator(Generator),
  Connector(Connector),
}

fn main() {
  let data = r#"
- source: "generator-01"
  id: "g-01"
  type: "Generator"
- source: "connector-01"
  type: "Connector"
  id: "c-01"
"#;
  let p: Vec<Box<dyn Model>> = serde_yaml::from_str(&data).unwrap();
  println!("{:?}", p);
}


impl From<AllModels> for Box<dyn Model> {
    fn from(am: AllModels) -> Self {
        Box::new(Generator{id:String::from("arst"),source_id:String::from("arst")})
    }
}
// impl Serialize for dyn Model {
//     fn serialize(&self) -> Self {
//         Box::new(Generator{id:String::from("arst"),source_id:String::from("arst")})
//     }
// }
impl Deserialize<'_> for dyn Model {}
impl From<Box<dyn Model>> for AllModels {
    fn from(dm: Box<dyn Model>) -> Self {
        AllModels::Generator(Generator{id:String::from("arst"),source_id:String::from("arst")})
    }
}

// impl std::convert::From<AllModels> for Box<dyn Model> {
//     fn from(m: AllModels) -> Self {
//        Box::new(Generator {source_id: String::from("i"), id: String::from("r")})
//     }
//     }

 ❯ cargo r
   Compiling serdeissue v0.1.0 (/sandbox/serdeissue)
warning: unused imports: `Deserializer`, `Serializer`, `serialize_trait_object`
 --> src/main.rs:1:20
  |
1 | use erased_serde::{Deserializer,  Serializer, serialize_trait_object};
  |                    ^^^^^^^^^^^^   ^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error[E0277]: the size for values of type `(dyn Model + 'static)` cannot be known at compilation time
   --> src/main.rs:76:6
    |
76  | impl Deserialize<'_> for dyn Model {}
    |      ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
   ::: /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/de/mod.rs:530:29
    |
530 | pub trait Deserialize<'de>: Sized {
    |                             ----- required by this bound in `Deserialize`
    |
    = help: the trait `Sized` is not implemented for `(dyn Model + 'static)`
❯ cargo r
   Compiling serdeissue v0.1.0 (/sandbox/serdeissue)
error[E0603]: module `export` is private
   --> src/main.rs:168:10
    |
168 | #[derive(Serialize)]
    |          ^^^^^^^^^ private module
    |
note: the module `export` is defined here
   --> /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/lib.rs:275:5
    |
275 | use self::__private as export;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0603]: module `export` is private
   --> src/main.rs:173:10
    |
173 | #[derive(Serialize)]
    |          ^^^^^^^^^ private module
    |
note: the module `export` is defined here
   --> /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/lib.rs:275:5
    |
275 | use self::__private as export;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0603]: module `export` is private
   --> src/main.rs:179:10
    |
179 | #[derive(Serialize)]
    |          ^^^^^^^^^ private module
    |
note: the module `export` is defined here
   --> /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/lib.rs:275:5
    |
275 | use self::__private as export;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0603]: module `export` is private
   --> src/main.rs:184:10
    |
184 | #[derive(Serialize)]
    |          ^^^^^^^^^ private module
    |
note: the module `export` is defined here
   --> /home/marcin/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/lib.rs:275:5
    |
275 | use self::__private as export;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: trait objects without an explicit `dyn` are deprecated
   --> src/main.rs:176:22
    |
176 |     widgets: Vec<Box<WidgetTrait>>,
    |                      ^^^^^^^^^^^ help: use `dyn`: `dyn WidgetTrait`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
[package]
name = "enum_unpack"
version = "0.1.0"
authors = ["---"]
edition = "2018"

[dependencies]
serde = { version = "1.0.124", features = ["derive"] }
serde_yaml = "0.8.1"
enum_dispatch = "0.3.5"