首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在多个“编码器”之间共享可变编写器?

如何在多个“编码器”之间共享可变编写器?
EN

Stack Overflow用户
提问于 2019-04-14 10:58:22
回答 1查看 87关注 0票数 0

我正在实现一个数据压缩接口:

代码语言:javascript
运行
复制
pub trait NumericEncoder<V> {
    fn encode(&mut self, value: V) -> io::Result<()>;
}

编码器可以在某种类型的输出中对某些数字进行编码,其中输出可以是流(文件)、字节缓冲区,甚至是另一个编码器。人们可能会像这样调用实现:

代码语言:javascript
运行
复制
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();

这一切都很好,但在某些情况下,我需要针对同一个输出流使用多个编码器。类似于(简化):

代码语言:javascript
运行
复制
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;有没有更好的方法?

据我所知,这会使所有的编码器实现变得不那么干净。现在可以像这样声明一个编码器:

代码语言:javascript
运行
复制
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。这不会起作用,因为有些编码器不会写入std::io::Write,而是写入另一个NumericEncoder。)

EN

回答 1

Stack Overflow用户

发布于 2019-04-14 21:15:37

实现此目的的唯一方法是使用RefCell

任何赋予内部可变性的类型都可以工作。例如,Mutex也足够了。

这将使所有编码器实现变得不那么整洁

我不知道你为什么这么想。创建一个使用内部可变性的类型,并仅在需要额外功能时使用该类型:

代码语言:javascript
运行
复制
#[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)
    }
}
代码语言:javascript
运行
复制
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 -我的代码不需要。

另请参阅:

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55671605

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档