我正在实现数据压缩接口:
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>,
}
使用RefCell
时,每个编码器结构和构造函数都需要处理Rc<RefCell<W>>
,这不是很好,并且会将编写器的共享性泄漏到编码器中,这不需要知道作家是共享的。
(我确实考虑过是否可以更改NumericEncoder
特质以接受写作者参数,该参数必须为std::io::Write
。这不起作用,因为某些编码器没有写出{ {1}},但移至另一个std::io::Write
。)
答案 0 :(得分:1)
唯一的方法是使用
RefCell
任何允许内部可变性的类型都可以使用。例如,Mutex
也足够。
这将使所有编码器实现的简洁程度降低
我不知道你为什么这么相信。创建一个使用内部可变性的类型,并且仅在需要其他功能时才使用该类型:
#[derive(Debug)]
struct Funnel<E>(Rc<RefCell<E>>);
impl<E> Funnel<E> {
fn new(e: E) -> Self {
Funnel(Rc::new(RefCell::new(e)))
}
}
impl<E> Clone for Funnel<E> {
fn clone(&self) -> Self {
Funnel(self.0.clone())
}
}
impl<V, E> NumericEncoder<V> for Funnel<E>
where
E: NumericEncoder<V>,
{
fn encode(&mut self, value: V) -> io::Result<()> {
self.0.borrow_mut().encode(value)
}
}
fn main() -> io::Result<()> {
let s = Shared;
let s1 = Funnel::new(s);
let s2 = s1.clone();
let mut e1 = Wrapper(s1);
let mut e2 = Wrapper(s2);
e1.encode(1)?;
e2.encode(2)?;
Ok(())
}
您还应该考虑按值取W
,但我不确定为什么需要PhantomData
-我的代码不需要。
另请参阅: