我正在实现一个数据压缩接口:
pub trait NumericEncoder<V> {
fn encode(&mut self, value: V) -> io::Result<()>;
}
编码器可以在某种输出中编码一些数字,其中输出可能是流(文件)、字节缓冲区甚至另一个编码器。可能会调用这样的实现:
let f = File::create("out").unwrap();
// Delta encoder whose data is run-length-compressed
let mut enc = DeltaEncoder::new(RunLengthEncoder::new(f));
enc.encode(123).unwrap();
这一切都很好,但在某些情况下,我需要针对同一个输出流的多个编码器。类似(简化):
let f = File::create("out")?;
let mut idEnc = RunLengthEncoder::new(DeltaEncoder::new(f));
let mut dataEnc = LZEncoder::new(f);
for (id, data) in input.iter() {
idEnc.encode(id);
dataEnc.encode(data);
}
在这里,两个编码器将在写入数据时交错数据。
&mut
这需要对同一文件进行可变访问,而直接引用则无法做到这一点。据我所知,实现这一点的唯一方法是使用RefCell
; 有没有更好的办法?
据我所知,这会使所有编码器实现变得不那么干净。现在可以像这样声明编码器:
pub struct MySpecialEncoder<'a, V, W>
where
W: io::Write,
{
w: &'a mut W,
phantom: std::marker::PhantomData<V>,
}
使用 a RefCell
,每个编码器结构和构造函数都需要处理Rc<RefCell<W>>
,这不是很好,并且会将编写器的共享性泄漏到编码器中,而编码器不需要知道编写器是共享的。
(我确实考虑过是否可以更改NumericEncoder
特征以采用 writer 参数,这必须是std::io::Write
。这不起作用,因为某些编码器不写入 a std::io::Write
,而是写入另一个NumericEncoder
。)