如何使用`emit_struct`和`emit_struct_field`序列化自定义结构?

时间:2015-04-12 14:01:30

标签: serialization rust

我已经阅读过Valve JSON Serialization in Rust, Part 1并尝试运行博客中的代码。最复杂的部分是为自定义结构执行自定义序列化。

我更新了代码段,以便它可以在最新的Rust上运行:

extern crate rustc_serialize;
use rustc_serialize::{json, Encodable, Encoder};

struct Person {
    name: String,
    age: usize,
}

impl Encodable for Person {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Person { name: ref p_name, age: ref p_age, } => {
                s.emit_struct("Person", 0, |s| {
                    try!(s.emit_struct_field( "name", 0, |s| p_name.encode(s)));
                    try!(s.emit_struct_field( "age", 1, |s| p_age.encode(s)));
                    try!(s.emit_struct_field( "summary", 2, |s| {
                        (format!("Nice person named {}, {} years of age", p_name, p_age)).encode(s)
                    }));
                    Ok(())
                })
            },
        }
    }
}

fn main() {
    let person = Person {
        name: "John Doe".to_string(),
        age: 33,
    };
    println!("{}" , json::encode(&person).unwrap());
}

上面的输出是{},但正确的结果应该是:

{"age":33,"name":"John Doe","summary":"Nice person named John Doe, 33 years of age"}

我想知道如何使用Encodable特征以正确的方式序列化自定义结构。

谢谢。

2 个答案:

答案 0 :(得分:3)

看起来你的教程已经过时了。它说

  

我们在编码器上调用emit_struct并传递3个参数:struct的名称,当前索引和匿名函数(aka lambda)。不使用结构的名称; 当前索引未被使用

但是the code says

fn emit_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult<()> where
    F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>,
{
    if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
    if len == 0 {
        try!(write!(self.writer, "{{}}"));

因此,参数已从索引更改为 length ,现在它有意义了。这是你工作的例子:

extern crate rustc_serialize;
use rustc_serialize::{json, Encodable, Encoder};

struct Person {
    name: String,
    age: usize,
}

impl Encodable for Person {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("Person", 1, |s| {
            try!(s.emit_struct_field("name",    0, |s| self.name.encode(s)));
            try!(s.emit_struct_field("age",     1, |s| self.age.encode(s)));
            try!(s.emit_struct_field("summary", 2, |s| {
                let summary = format!("Nice person named {}, {} years of age", self.name, self.age);
                summary.encode(s)
            }));
            Ok(())
        })
    }
}

fn main() {
    let person = Person {
        name: "John Doe".to_string(),
        age: 33,
    };
    println!("{}" , json::encode(&person).unwrap());
}

请注意,我还删除了疯狂的旋转来解构self并直接访问属性。

答案 1 :(得分:2)

问题在于emit_struct(..)来电。

此功能的原型是:

fn emit_struct<F>(&mut self, name: &str, len: usize, f: F)
    -> Result<(), Self::Error>
    where F: FnOnce(&mut Self) -> Result<(), Self::Error>;

此处,len是结构的字段数。你把它设置为0,因此生成的JSON字典有0个字段。

将其更改为3可得出此输出:

{"name":"John Doe","age":33,"summary":"Nice person named John Doe, 33 years of age"}