在Rust中将JSON值解析为Enum

时间:2014-09-01 10:59:30

标签: rust

我有包含原语的枚举:

#[deriving(Decodable)]
enum MyValue {
  MyString(String),
  MyF64(f64),
  MyF32(f32),
  MyI64(i64),
  MyI32(i32),
  ...
  ...
}

现在我想将JSON字符串转换为MyValue的相应变体,例如:

let v: MyValue = parse_json("3.14") // MyF32(3.14f32)
let v: MyValue = parse_json("3.14151515151515") // MyF64(3.14151515151515f64)
let v: MyValue = parse_json("42") // MyI32(42)
let v: MyValue = parse_json("\"hello\"") // MyString("hello")

如果我直接这样做:

let my_value: MyValue = json::decode("3.14").unwrap();

我明白了:

task '<main>' failed at 'called结果::的unwrap()on an {ERR {1}}

是否可以仅使用Rust类型系统进行上述操作?

如果没有,应该采取什么方法?我应该使用正则表达式/ PEG解析器还是别的什么?

playpen

1 个答案:

答案 0 :(得分:4)

我怀疑你能用#[deriving(Decodable)]做到这一点。这是由rustc --pretty expanded生成的片段:

__arg_0.read_enum("MyValue", |_d|
    _d.read_enum_variant(["MyString", "MyF64", "MyF32", "MyI64", "MyI32"], |_d, i|
        ::std::result::Ok(match i {
            0u => MyString(match _d.read_enum_variant_arg(0u, |_d| ::serialize::Decodable::decode(_d)) {
                Ok(__try_var) => __try_var,
                Err(__try_var) => return Err(__try_var),
            }),
            1u => MyF64(match _d.read_enum_variant_arg(0u, |_d| ::serialize::Decodable::decode(_d)) {
                Ok(__try_var) => __try_var,
                Err(__try_var) => return Err(__try_var),
            }),
            2u => ...

即,它调度解码器提供的枚举变量索引。事实上,兼容的JSON看起来像这样,你可以see it yourself

{ "variant": 1, "fields": [12345] }  // corresponds to MyF64(12345)

一般来说,我认为无法在任何语言中执行您想要的操作,而不仅仅是在Rust中。例如,JSON不够复杂,无法区分不同类型的整数。另外,Rust Decodable特征要求您确定使用某种元数据解码的枚举的确切变体;你不能在那里读取任意值并在运行时决定它的类型。所以你需要自己编写一些解析器,但是,我强烈建议你重新考虑你在做什么。 JSON可能不是您需要的语言。