【问题标题】:Deserialize to struct with an enum member反序列化为带有枚举成员的结构
【发布时间】:2016-02-01 15:52:08
【问题描述】:

我正在尝试获取一些看起来像这样的 json:

{
    "foo": "bar",
    "name": "some name"
}

并使用serde 将其反序列化为如下数据结构:

#[derive(Clone, PartialEq, Debug)]
pub struct Quux {
    foo: Foo,
    name: String,

}

pub enum Foo {
    Bar,
    Baz,
}

have some code,但老实说,它几乎直接来自 serde 指南“不使用宏进行反序列化”,我不确定我需要做什么才能使其反序列化将foo 字段转换为Foo

我已经为Foo 枚举实现了Deserialize,我认为这足以让我的impl serde::de::Vistor for QuuxVisitor 中的visitor.visit_value() 调用调用该版本的deserialize,但似乎并非如此.

当我尝试反序列化为Quux 时遇到的错误是called 'Result::unwrap()' on an 'Err' value: SyntaxError("expected value", 2, 20),但如果我将Quux 更改为使用Stringfoo 而不是Foo,它反序列化很好。

【问题讨论】:

    标签: json rust deserialization serde


    【解决方案1】:

    有 Rust 1.18 / serde 1.0.0 的完整示例:

    impl<'de> Deserialize<'de> for EventKind {
        fn deserialize<D>(deserializer: D) -> result::Result<EventKind, D::Error>
            where D: Deserializer<'de>
        {
            struct FieldVisitor {
                min: usize,
            };
    
            impl<'de> Visitor<'de> for FieldVisitor {
                type Value = EventKind;
    
                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    write!(formatter, "a string containing at least {} bytes", self.min)
                }
    
                fn visit_str<E>(self, value: &str) -> result::Result<EventKind, E>
                    where E: serde::de::Error
                {
                    let kind = match value {
                        "request" => EventKind::Request,
                        "ready" => EventKind::Ready,
                        "next" => EventKind::Next,
                        "reject" => EventKind::Reject,
                        "fail" => EventKind::Fail,
                        "done" => EventKind::Done,
                        "cancel" => EventKind::Cancel,
                        "suspended" => EventKind::Suspended,
                        s => {
                            return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s),
                                                                       &self));
                        }
                    };
                    Ok(kind)
                }
            }
            deserializer.deserialize_str(FieldVisitor { min: 4 })
        }
    }
    
    enum EventKind {
        Request,
        Ready,
        Next,
        Reject,
        Fail,
        Done,
        Cancel,
        Suspended,
    }
    
    impl Serialize for EventKind {
        fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
            where S: Serializer
        {
            let kind = match *self {
                EventKind::Request => "request",
                EventKind::Ready => "ready",
                EventKind::Next => "next",
                EventKind::Reject => "reject",
                EventKind::Fail => "fail",
                EventKind::Done => "done",
                EventKind::Cancel => "cancel",
                EventKind::Suspended => "suspended",
            };
            serializer.serialize_str(kind)
        }
    }
    

    你可以看到一个类似的例子here

    【讨论】:

      【解决方案2】:

      这是一个例子。我不确定处理未知字段的最佳方法,但这有效:

      extern crate serde;
      
      use serde::de::{Deserialize, Deserializer, Visitor, Error};
      
      pub enum Foo {
          Bar,
          Baz,
      }
      
      impl Deserialize for Foo {
          fn deserialize<D>(deserializer: &mut D) -> Result<Foo, D::Error>
              where D: Deserializer
          {
              struct FieldVisitor;
      
              impl Visitor for FieldVisitor {
                  type Value = Foo;
      
                  fn visit_str<E>(&mut self, value: &str) -> Result<Foo, E>
                      where E: Error
                  {
                      match value {
                          "bar" => Ok(Foo::Bar),
                          "baz" => Ok(Foo::Baz),
                          _ => Err(E::syntax(&format!("Unexpected field: {}", value))),
                      }
                  }
              }
      
              deserializer.visit(FieldVisitor)
          }
      }
      

      我使用的是 Rust 1.6。

      【讨论】:

      • 是的,这将反序列化枚举,但是当结构具有类型为enum Foo 的成员时,反序列化结构不会使用Deserialize impl for Foo
      【解决方案3】:

      我建议使用serde_derive 来生成Deserialize 实现,而不是手动写出来。

      在下面的代码中,我使用#[serde(rename_all = "lowercase")] 使Foo 接受JSON 表示"bar""baz",而不是默认的"Bar""Baz",对应于Rust 代码中的大小写。

      #[macro_use]
      extern crate serde_derive;
      extern crate serde;
      
      #[derive(Deserialize, Debug)]
      struct Quux {
          foo: Foo,
          name: String,
      }
      
      #[derive(Deserialize, Debug)]
      #[serde(rename_all = "lowercase")]
      enum Foo {
          Bar,
          Baz,
      }
      
      fn main() {
          let j = r#"
              {
                  "foo": "bar",
                  "name": "some name"
              }
              "#;
      
          println!("{:#?}", serde_json::from_str::<Quux>(j).unwrap());
      }
      

      【讨论】:

        猜你喜欢
        • 2021-09-26
        • 2014-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-31
        • 2015-07-26
        相关资源
        最近更新 更多