我有一个我想要编码为JSON的结构。此结构包含类型为Option<i32>
的字段。我们说
extern crate rustc_serialize;
use rustc_serialize::json;
#[derive(RustcEncodable)]
struct TestStruct {
test: Option<i32>
}
fn main() {
let object = TestStruct {
test: None
};
let obj = json::encode(&object).unwrap();
println!("{}", obj);
}
这会给我输出
{"test": null}
是否有一种方便的方法可以省略值为Option
的{{1}}字段?在这种情况下,我想要输出
None
答案 0 :(得分:2)
如果有人和我一样带着同样的问题来到这里,serde 现在有一个选项 skip_serializing_none 来做到这一点。
https://docs.rs/serde_with/1.8.0/serde_with/attr.skip_serializing_none.html
答案 1 :(得分:0)
通过纯粹从结构中进行似乎不可能,所以我将结构转换为字符串,然后将其转换为JSON对象。此方法要求所有Option
类型都是相同的类型。我建议你是否需要在结构中使用变量类型将它们首先变成字符串。
field_vec
和field_name_vec
必须在编译时填充所有字段,因为我无法找到获取字段值的方法,而字段名称在不知道它们生锈的情况下运行时间。
extern crate rustc_serialize;
use rustc_serialize::json::Json;
fn main() {
#[derive(RustcEncodable)]
struct TestStruct {
test: Option<i32>
}
impl TestStruct {
fn to_json(&self) -> String {
let mut json_string = String::new();
json_string.push('{');
let field_vec = vec![self.test];
let field_name_vec = vec![stringify!(self.test)];
let mut previous_field = false;
let mut count = 0;
for field in field_vec {
if previous_field {
json_string.push(',');
}
match field {
Some(value) => {
let opt_name = field_name_vec[count].split(". ").collect::<Vec<&str>>()[1];
json_string.push('"');
json_string.push_str(opt_name);
json_string.push('"');
json_string.push(':');
json_string.push_str(&value.to_string());
previous_field = true;
},
None => {},
}
count += 1;
}
json_string.push('}');
json_string
}
}
let object = TestStruct {
test: None
};
let object2 = TestStruct {
test: Some(42)
};
let obj = Json::from_str(&object.to_json()).unwrap();
let obj2 = Json::from_str(&object2.to_json()).unwrap();
println!("{:?}", obj);
println!("{:?}", obj2);
}
答案 2 :(得分:0)
要省略Option<T>
字段,您可以创建Encodable
特征的实现(而不是使用#[derive(RustcEncodable)]
)。
在这里,我更新了您的示例以执行此操作。
extern crate rustc_serialize;
use rustc_serialize::json::{ToJson, Json};
use rustc_serialize::{Encodable,json};
use std::collections::BTreeMap;
#[derive(PartialEq, RustcDecodable)]
struct TestStruct {
test: Option<i32>
}
impl Encodable for TestStruct {
fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
self.to_json().encode(s)
}
}
impl ToJson for TestStruct {
fn to_json(&self) -> Json {
let mut d = BTreeMap::new();
match self.test {
Some(value) => { d.insert("test".to_string(), value.to_json()); },
None => {},
}
Json::Object(d)
}
}
fn main() {
let object = TestStruct {
test: None
};
let obj = json::encode(&object).unwrap();
println!("{}", obj);
let decoded: TestStruct = json::decode(&obj).unwrap();
assert!(decoded==object);
}
最好实现一个自定义#[derive]
宏,它会自动为Option
字段执行此操作,因为这样就不需要Encodable
这样的自定义实现。