排水迭代器是一個有趣的野獸。它們允許您將某個集合的一部分分割出來,從而獲得集合中某些但不一定是所有項目的所有權。他們還允許您以合理高效的方式執行此操作。例如,矢量可以將尾隨數據整體與單個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::Serialize
或vec::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
。
序列化和排空有什麼問題? –