我想将第三方库枚举转换为JSON和从JSON转换。因为我不想编辑第三方源代码,所以我不想使用派生宏。
我想手写serde_json deserialize
方法。我认为模式匹配是要走的路,但我需要匹配的东西不公开:
extern crate serde_json;
#[test]
fn test_parse_from_json() {
let s = r#"{
"e": 0,
"c": 1,
"n": 2
}"#;
let v: Map<String, Value> = serde_json::from_str(&s).unwrap();
match (&v["e"], &v["c"], &v["n"]) {
(&Value::Number(ref e), &Value::Number(ref c), &Value::Number(ref n)) => {
// e is a PosInt(u64) but that isn't public to match one nor access its methods!
let value = e.n; // error[E0616]: field `n` of struct `serde_json::Number` is private
}
_ => (),
}
}
那不编译。如果我用可以设置断点的东西替换那个内部位,我可以在调试器中看到e
是Number
,其中包含PosInt(0)
。
答案 0 :(得分:1)
您不能在私有字段上进行模式匹配,因为它们是私有的。您必须使用库决定提供的访问器。 Number
的serde_json文档显示它包含as_u64
:
let value = e.as_u64().expect("not a u64");
由于我不想编辑第三方源代码,所以我不想使用派生宏。
您可能会受到X-Y problem的影响。例如,Serde文档描述了如何implement the traits for a "remote type"。
您还可以创建自己的类型,然后反序列化并构建与库类型之间的转换:
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[derive(Deserialize)]
struct Mine {
e: u64,
c: u64,
n: u64,
}
#[test]
fn test_parse_from_json() {
let s = r#"{
"e": 0,
"c": 1,
"n": 2
}"#;
let v: Mine = serde_json::from_str(&s).unwrap();
println!("{:?}", (v.e, v.c, v.n));
}
答案 1 :(得分:0)
根据@ Shepmaster的回答,我得到了更多的进展:
let v: Map<String, Value> = serde_json::from_str(&s).unwrap();
let bn: Option<BallotNumber>;
match (&v["e"],&v["c"],&v["n"]) {
(&Value::Number(ref e),&Value::Number(ref c),&Value::Number(ref n)) => {
match ( &e.as_u64(), &c.as_u64(), &n.as_u64() ) {
(&Some(era), &Some(count), &Some(number)) =>
bn = Some(BallotNumber::new(era, count, number)),
_ =>
bn = None
}
},
_ =>
bn = None
}
这就是诀窍,只是看起来有点火车粉碎。鉴于@ Shepmaster的回答指出serde提供了绕Orphan规则的方法,我将使用这种方法。