简体   繁体   English

Rust Json序列化重叠职责

[英]Rust Json serialization overlapping responsibilities

I'm learning Json serialization in Rust, in particular, how to serialize Rust objects to Json. 我正在学习Rust中的Json序列化,特别是如何将Rust对象序列化为Json。

Currently I see 3 methods of converting an instance of a struct to Json: 目前我看到3种将结构实例转换为Json的方法:

  1. Deriving Encodable trait 推导可编码特征

  2. Manual implementation of ToJson trait 手动实施ToJson特质

  3. Manual implementation of Encodable trait 手动实现Encodable特征

Below code illustrates all 3 approaches: 以下代码说明了所有3种方法:

extern crate serialize;

use serialize::{Encoder, Encodable, json};
use serialize::json::{Json, ToJson};
use std::collections::TreeMap;

fn main() {
  let document = Document::new();
  let word_document = WordDocument::new();
  println!("1. Deriving `Encodable`: {}", json::encode(&document));
  println!("2. Manually implementing `ToJson` trait: {}", document.to_json());
  println!("3. Manually implementing `Encodable` trait: {}", json::encode(&word_document));
}

#[deriving(Encodable)]
struct Document<'a> {
  metadata: Vec<(&'a str, &'a str)>
}

impl<'a> Document<'a> {
  fn new() -> Document<'a> {
    let metadata = vec!(("Title", "Untitled Document 1"));
    Document {metadata: metadata}
  }
}

impl<'a> ToJson for Document<'a> {
  fn to_json(&self) -> Json {
    let mut tm = TreeMap::new();
    for &(ref mk, ref mv) in self.metadata.iter() {
      tm.insert(mk.to_string(), mv.to_string().to_json());
    }
    json::Object(tm)
  }
}

struct WordDocument<'a> {
  metadata: Vec<(&'a str, &'a str)>
}

impl<'a> WordDocument<'a> {
  fn new() -> WordDocument<'a> {
    let metadata = vec!(("Title", "Untitled Word Document 1"));
    WordDocument {metadata: metadata}
  }
}

impl<'a, E, S: Encoder<E>> Encodable<S, E> for WordDocument<'a> {
  fn encode(&self, s: &mut S) -> Result<(), E> {
    s.emit_map(self.metadata.len(), |e| {
      let mut i = 0;
      for &(ref key,  ref val) in self.metadata.iter() {
        try!(e.emit_map_elt_key(i, |e| key.encode(e)));
        try!(e.emit_map_elt_val(i, |e| val.encode(e)));
        i += 1;
      }
      Ok(())
    })
  }
}

Rust playpen: http://is.gd/r7cYmE Rust围栏: http//is.gd/r7cYmE

Results: 结果:

1. Deriving `Encodable`: {"metadata":[["Title","Untitled Document 1"]]}
2. Manually implementing `ToJson` trait: {"Title":"Untitled Document 1"}
3. Manually implementing `Encodable` trait: {"Title":"Untitled Word Document 1"}

First method is fully automatic, but does not provide sufficient flexibility. 第一种方法是全自动的,但没有提供足够的灵活性。 Second and third achieve same level of flexibility by specifying the serialization process manually. 第二个和第三个通过手动指定序列化过程实现相同级别的灵活性。 In my case I want document metadata to be serialized as an object, not as an array (which is what deriving implementation gives me). 在我的情况下,我希望将文档元数据序列化为一个对象,而不是一个数组(这是派生实现给我的)。

Questions : 问题

  1. Why do methods 2 and 3 exist at all? 为什么方法2和3都存在? I don't understand the reason for the overlap between them. 我不明白他们之间重叠的原因。 I would expect there to exist only one automatic (deriving) method of serialization and one manual. 我希望只存在一种自动(派生)序列化方法和一本手册。
  2. If I want manual serialization, which method should I choose and why? 如果我想手动序列化,我应该选择哪种方法?为什么?

  3. Am I right in assuming that method 2 will build a Json enum in memory (besides the struct itself) and is a worse fit for huge documents (multi megabytes), while method 3 is streaming and safer for huge documents? 我是否正确假设方法2将在内存中构建一个Json枚举(除了结构本身)并且更适合于大型文档(多兆字节),而方法3是流式传输并且对于大型文档更安全?

  4. Why does rust stdlib use method 3 even for primitives, while not using method 2 internally? 为什么rust stdlib使用方法3甚至是原语,而不是在内部使用方法2?

Why do methods 2 and 3 exist at all? 为什么方法2和3都存在? I don't understand the reason for the overlap between them. 我不明白他们之间重叠的原因。 I would expect there to exist only one automatic (deriving) method of serialization and one manual. 我希望只存在一种自动(派生)序列化方法和一本手册。

Method 2 (the ToJson trait) is specific to encoding JSON. 方法2( ToJson特征)特定于编码JSON。 It returns JSON objects, instead of writing to a stream. 它返回JSON对象,而不是写入流。 One example of use is for mapping to custom representations - see this example in the documentation. 使用的一个示例是映射到自定义表示 - 请参阅文档中的此示例

Method 3 (implementing Encodable ) has to exist for method 1 to work. 方法1必须存在方法3(实现Encodable )才能工作。

Am I right in assuming that method 2 will build a Json enum in memory (besides the struct itself) and is a worse fit for huge documents (multi megabytes), while method 3 is streaming and safer for huge documents? 我是否正确假设方法2将在内存中构建一个Json枚举(除了结构本身)并且更适合于大型文档(多兆字节),而方法3是流式传输并且对于大型文档更安全?

Yes. 是。 ToJson creates a nested Json enum of the whole object, while Encodable streams to a Writer . ToJson创建整个对象的嵌套Json枚举,而Encodable流式传输到Writer

If I want manual serialization, which method should I choose and why? 如果我想手动序列化,我应该选择哪种方法?为什么?

Why does rust stdlib use method 3 even for primitives, while not using method 2 internally? 为什么rust stdlib使用方法3甚至是原语,而不是在内部使用方法2?

You should use Encodable . 你应该使用Encodable It is not specific to the JSON format, does not use an intermediate representation (so can be streamed instead of stored in memory) and should continue to work with new formats added to the library. 它不是特定于JSON格式,不使用中间表示(因此可以流式传输而不是存储在内存中)并且应该继续使用添加到库中的新格式。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM