2015-12-21 53 views
1

我想drain()在鏽vec和編碼結果作爲一個JSON字符串。什麼是最好的,慣用的方式來做到這一點?什麼是用serde_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

序列化和排空有什麼問題? –

回答

3

排水迭代器是一個有趣的野獸。它們允許您將某個集合的一部分分割出來,從而獲得集合中某些但不一定是所有項目的所有權。他們還允許您以合理高效的方式執行此操作。例如,矢量可以將尾隨數據整體與單個memcpy一起移動。

然而,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,我們也必須創建一個新類型以將其實施。

我們可以概括這個解決方案適用於任何迭代器。出現這種情況,使之讀更好一點,在我看來:

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

相關問題