如何进行模式匹配以获得 serde_json 已解析的数字?

How can I pattern match to get at the numbers that serde_json has parsed?

我想将第 3 方库枚举与 JSON 相互转换。因为我不想编辑第 3 方源代码,所以我不想使用派生宏。

我想手写serde_jsondeserialize方法。我认为模式匹配是可行的方法,但我需要匹配的东西不是 public:

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 是一个包含 PosInt(0)Number

您不能对私有字段进行模式匹配,因为它们是私有的。您必须使用图书馆决定提供的访问器。 Number shows that it has methods like as_u64 的 serde_json 文档:

let value = e.as_u64().expect("not a u64");

As I don't want to edit the 3rd party source code I don't want to use the derive macros.

您可能正在遭受X-Y problem. For example, the Serde docs describe how to 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));
}

根据@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 提供了一种绕过孤儿规则的方法,我将使用该方法。