用serde_json编码迭代器的惯用方法是什么?

时间:2015-12-21 15:47:46

标签: json rust encode serde

我尝试在Rust中drain() vec并将结果编码为JSON字符串。这是最好的,惯用的方法吗?

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

extern crate serde;
extern crate serde_json;

#[derive(Serialize, Deserialize, Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl Point {
    pub fn new(x: i32, y: i32) -> Point {
        Point {
            x: x,
            y: y
        }
    }
}

fn main() {
    let mut points = vec![Point::new(1,2), Point::new(-2,-1), Point::new(0, 0)];
    let mut drain = points.drain(..);

    println!("{}", serde_json::to_string(&drain).unwrap());
}

1 个答案:

答案 0 :(得分:4)

排放迭代器是一个有趣的野兽。它们允许您将集合的一部分分块,获取集合中的一些但不一定是所有项目的所有权。它们还允许您以合理有效的方式执行此操作。例如,向量可以使用单个memcpy移动尾随数据 en masse

但是,serde本身不支持序列化迭代器(有充分的理由,请继续阅读)。您可以查看Serialize trait以查看它支持的内容类型。

你必须自己实现这个:

use serde::ser::impls::SeqIteratorVisitor;
use std::cell::RefCell;
use std::vec;

struct DrainIteratorAdapter<'a, T: 'a>(RefCell<vec::Drain<'a, T>>);

impl<'a, T: 'a> serde::Serialize for DrainIteratorAdapter<'a, T>
    where T: serde::Serialize
{
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: serde::Serializer
    {
        let mut iter = self.0.borrow_mut();
        // Use `size_hint` here?
        serializer.visit_seq(SeqIteratorVisitor::new(iter.by_ref(), None))
    }
}

fn main() {
    let mut points = vec![Point::new(1, 2), Point::new(-2, -1), Point::new(0, 0)];
    let adapter = DrainIteratorAdapter(RefCell::new(points.drain(..)));

    println!("{}", serde_json::to_string(&adapter).unwrap());
}

核心难点在于序列化应该没有任何副作用。这是一个非常合理的决定。但是,无论何时在迭代器上调用next,都必须对其进行变更才能更新状态。要结合这两个不匹配的概念,我们必须使用RefCell

之类的东西

除此之外,这只是实施serde::Serialize trait的问题。由于我们既不拥有serde::Serializevec::Drain,我们必须创建一个 newtype 来放置实现。

我们可以将此解决方案概括为适用于任何迭代器。在我看来,这恰好使它读得更好一些:

use serde::ser::impls::SeqIteratorVisitor;
use std::cell::RefCell;

struct IteratorAdapter<I>(RefCell<I>);

impl<I> serde::Serialize for IteratorAdapter<I>
    where I: Iterator,
          I::Item: serde::Serialize,
{
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: serde::Serializer
    {
        let mut iter = self.0.borrow_mut();
        // Use `size_hint` here?
        serializer.visit_seq(SeqIteratorVisitor::new(iter.by_ref(), None))
    }
}

此解决方案的缺点是什么? 两次序列化相同的值会产生不同的结果!如果我们只是序列化并打印两次值,我们会得到:

[{"x":1,"y":2},{"x":-2,"y":-1},{"x":0,"y":0}]
[]

这是因为迭代器是瞬态动物 - 一旦它们读取了一个值,它就消失了!这是一个很好的陷阱,等着你陷入其中。

在你的例子中,这一切都没有意义。您可以访问整个Vec,因此您可以在此处序列化它(或其中的一部分)。此外,没有理由(现在)drain整个集合。这相当于只调用into_iter