是否可以为struct的一部分派生(RustcEncodable)?

时间:2016-05-18 00:25:57

标签: rust

我有一个结构:

struct S {
    data: i32,
    fun: Box<Fn()>,
}

并希望使用编码器序列化数据部分。为此,我使用rustc_serialize并派生其特征,如

#[derive(RustcEncodable, RustcDecodable)]
struct S {
    data: i32,
    fun: Box<Fn()>,
}

问题是fun无法序列化,因为它是一个功能。这很好,因为我只想序列化普通的data字段。有没有办法做到这一点?

我的实际用例中的data字段也是一个结构,它也可以有一个Fn所以我不能简单地将结构分成两个。

2 个答案:

答案 0 :(得分:3)

简短的回答是“不”。 rustc-serialize crate 1 DecodableEncodable等特征的自动实现没有提供这种控制水平。

为此,您需要自己实施:

extern crate rustc_serialize;

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

struct S {
    data: i32,
    fun: Box<Fn()>,
}

impl Encodable for S {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("S", 1, |s| {
            s.emit_struct_field("data", 0, |s| {
                s.emit_i32(self.data)
            })
        })
    }
}

fn main() {
    let thing = S { data: 42, fun: Box::new(|| println!("I am a function")) };
    let json = json::encode(&thing).expect("Couldn't encode");
    println!("{}", json);
    (thing.fun)();
}

如果您不依赖于rustc-serialize,您可能会对提供#[serde(skip_serializing)]#[serde(skip_deserializing)]注释的serde感兴趣。

1 :从技术上讲,编译器提供了#[derive(RustcEncodable, RustcDecodable)] 。这就是它具有Rustc前缀的原因。它也是一个丑陋的疣,想要被删除,但正在等待编译器插件的稳定支持。

答案 1 :(得分:3)

Shepmaster's answer给出了RustcEncodable解决方案。为了完整起见,这里是等效的Serde代码:

#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde_json;

#[derive(Serialize, Deserialize)]
struct S {
    data: i32,
    #[serde(skip_serializing, skip_deserializing, default="empty_fun")]
    fun: Box<Fn()>,
}

fn empty_fun() -> Box<Fn()> {
    Box::new(|| {})
}

fn main() {
    let s = S { data: 42, fun: Box::new(|| println!("I am a function")) };

    // prints {"data":42}
    println!("{}", serde_json::to_string(&s).unwrap());
}

skip_serializing属性表示在序列化结构时忽略该字段。同样,skip_deserializing属性意味着在反序列化时忽略该字段。

default属性给出反序列化时用于字段的值。实施std::default::Default的字段不需要此字段,因为Serde可以使用Default::default()的值。