当前位置:  开发笔记 > 编程语言 > 正文

rustc-serialize自定义枚举解码

如何解决《rustc-serialize自定义枚举解码》经验,为你挑选了1个好方法。

我有一个JSON结构,其中结构的一个字段可以是对象,也可以是数据库中该对象的ID.假设文档看起来像这样两种可能的结构格式:

[
   {
      "name":"pebbles",
      "car":1
   },
   {
      "name":"pebbles",
      "car":{
         "id":1,
         "color":"green"
      }
   }
]

我正在试图找出为此实现自定义解码器的最佳方法.到目前为止,我尝试了几种不同的方式,我现在卡在这里:

extern crate rustc_serialize;

use rustc_serialize::{Decodable, Decoder, json};

#[derive(RustcDecodable, Debug)]
struct Car {
  id: u64,
  color: String
}

#[derive(Debug)]
enum OCar {
  Id(u64),
  Car(Car)
}

#[derive(Debug)]
struct Person {
  name: String,
  car: OCar
}

impl Decodable for Person {
  fn decode(d: &mut D) -> Result {
    d.read_struct("root", 2, |d| {
      let mut car: OCar;

      // What magic must be done here to get the right OCar?

      /* I tried something akin to this:
      let car = try!(d.read_struct_field("car", 0, |r| {
        let r1 = Car::decode(r);
        let r2 = u64::decode(r);

        // Compare both R1 and R2, but return code for Err() was tricky
      }));
      */

      /* And this got me furthest */
      match d.read_struct_field("car", 0, u64::decode) {
        Ok(x) => {
          car = OCar::Id(x);
        },
        Err(_) => {
          car = OCar::Car(try!(d.read_struct_field("car", 0, Car::decode)));
        }
      }


      Ok(Person {
        name: try!(d.read_struct_field("name", 0, Decodable::decode)),
        car: car
      })
    })
  }
}

fn main() {
  // Vector of both forms
  let input = "[{\"name\":\"pebbles\",\"car\":1},{\"name\":\"pebbles\",\"car\":{\"id\":1,\"color\":\"green\"}}]";

  let output: Vec = json::decode(&input).unwrap();

  println!("Debug: {:?}", output);
}

以上恐慌与EOL是一个哨兵值rustc-serialize使用它的一些错误枚举.全线是

thread '
' panicked at 'called `Result::unwrap()` on an `Err` value: EOF', src/libcore/result.rs:785

这样做的正确方法是什么?



1> Francis Gagn..:

rustc-serialize或者至少它的JSON解码器不支持该用例.如果你看的执行read_struct_field(或任何其他方法),你可以看到为什么:它使用了栈,但是当它遇到一个错误,它不打扰堆栈恢复为原始状态,所以当你尝试以不同的方式解码相同的东西,解码器在不一致的堆栈上操作,最终导致意外的EOF值.

我建议你看看Serde.在Serde中反序列化是不同的:不是告诉解码器你期望什么类型,并且没有明确的方法来恢复一个值是错误的类型,Serde调用访问者可以处理Serde支持的任何类型它想要的方式.这意味着Serde将根据其解析的值的实际类型调用访问者的不同方法.例如,我们可以处理整数来返回一个OCar::Id和对象来返回一个OCar::Car.

这是一个完整的例子:

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

extern crate serde;
extern crate serde_json;

use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Visitor};
use serde::de::value::MapVisitorDeserializer;

#[derive(Deserialize, Debug)]
struct Car {
    id: u64,
    color: String
}

#[derive(Debug)]
enum OCar {
    Id(u64),
    Car(Car),
}

struct OCarVisitor;

#[derive(Deserialize, Debug)]
struct Person {
    name: String,
    car: OCar,
}

impl Deserialize for OCar {
    fn deserialize(deserializer: &mut D) -> Result where D: Deserializer {
        deserializer.deserialize(OCarVisitor)
    }
}

impl Visitor for OCarVisitor {
    type Value = OCar;

    fn visit_u64(&mut self, v: u64) -> Result where E: Error {
        Ok(OCar::Id(v))
    }

    fn visit_map(&mut self, visitor: V) -> Result where V: MapVisitor {
        Ok(OCar::Car(try!(Car::deserialize(&mut MapVisitorDeserializer::new(visitor)))))
    }
}

fn main() {
    // Vector of both forms
    let input = "[{\"name\":\"pebbles\",\"car\":1},{\"name\":\"pebbles\",\"car\":{\"id\":1,\"color\":\"green\"}}]";

    let output: Vec = serde_json::from_str(input).unwrap();

    println!("Debug: {:?}", output);
}

输出:

Debug: [Person { name: "pebbles", car: Id(1) }, Person { name: "pebbles", car: Car(Car { id: 1, color: "green" }) }]

Cargo.toml:

[dependencies]
serde = "0.7"
serde_json = "0.7"
serde_macros = "0.7"


请参阅[使用Serde with Stable Rust和serde_codegen](https://github.com/serde-rs/serde#using-serde-with-stable-rust-and-serde_codegen).
推荐阅读
可爱的天使keven_464
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有