在Serde中处理混合对象数组

时间:2016-06-26 09:53:10

标签: json serialization rust serde

扩展我的previous question,如何处理包含有效structs的混合structs的数组?我试过看serde_json::Value来源了。但是它没有处理两个不同struct的情况。

我无法简单地合并它们,并在其属性上使用选项,因为这会使单#[derive(Clone, Debug, Deserialize)] struct WebResponse { foo: Vec<Structs>, } enum Structs { Foo(Foo), Bar(Bar), } #[derive(Clone, Debug, Deserialize)] struct Foo { name: String, baz: Vec<String>, } #[derive(Clone, Debug, Deserialize)] struct Bar { quux: u64 } 变得笨拙,并且对它们来说很重要。

Rust structs

{
    "foo": [
        {
            "name": "John",
            "baz": ["Lorem", "Ipsum"]
        },
        {
            "quux": 17
        }
    ]
}

示例JSON

public class Employee : INotifyPropertyChanged
    {
        public Employee()
        {
            _subEmployee = new ObservableCollection<Employee>();
        }

        private string _name;

        public ObservableCollection<Employee> SubEmployee
        {
            get { return _subEmployee; }
            set
            {
                _subEmployee = value;
                NotifiyPropertyChanged("SubEmployee");
            }
        }

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value; 
                NotifiyPropertyChanged("Name");
            }
        }

        ObservableCollection<Employee> _subEmployee;

        public event PropertyChangedEventHandler PropertyChanged;
        void NotifiyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

1 个答案:

答案 0 :(得分:5)

有几种方法可以解决这个问题。如果您的变体很少,最简单的方法就是手动实现Deserialize,如下所示:

impl serde::de::Deserialize for Structs {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: serde::Deserializer,
    {
        deserializer.deserialize(Visitor)
    }
}

struct Visitor;

impl serde::de::Visitor for Visitor {
    type Value = Structs;

    fn visit_map<V>(&mut self, mut visitor: V) -> Result<Structs, V::Error>
        where V: serde::de::MapVisitor,
    {
        let s: String = try!(visitor.visit_key()).expect("got struct with no fields");
        let val = match &s as &str {
            "name" => {
                Ok(Structs::Foo(Foo {
                    name: try!(visitor.visit_value()),
                    baz: {
                        let s: String = try!(visitor.visit_key()).expect("baz field");
                        assert_eq!(&s, "baz");
                        try!(visitor.visit_value())
                    },
                }))
            },
            "baz" => {
                Ok(Structs::Foo(Foo {
                    baz: try!(visitor.visit_value()),
                    name: {
                        let s: String = try!(visitor.visit_key()).expect("name field");
                        assert_eq!(&s, "name");
                        try!(visitor.visit_value())
                    },
                }))
            },
            "quux" => {
                Ok(Structs::Bar(Bar {
                    quux: try!(visitor.visit_value())
                }))
            },
            other => panic!("no struct has field `{}`", other),
        };
        try!(visitor.end());
        val
    }
}

此实现的问题在于它显然无法扩展。您可以做的是创建一个新的Deserializer,您可以为其找到第一个字段名称,并覆盖deserialize_map方法以通过自定义MapVisitor处理各种结构。< / p>

如果您认为这是其他序列化框架支持的常见情况,请随时在serde存储库或serde-json存储库上发布错误报告。我确信有一种方法可以自动生成这样的实现,但这肯定不是一件容易的事。