rust 带参数的特征对象函数

omvjsjqw  于 2023-03-02  发布在  其他
关注(0)|答案(1)|浏览(128)

我试图做一个简单的模板引擎(用于发送具有不同内容的消息),但遇到了一个问题,我不能使“虚拟”方法参数化。

trait Evaluatable {
    fn evaluate(&self, dest: &mut impl std::io::Write);
}

struct A {}
struct B {}

impl Evaluatable for A {
    
    fn evaluate(&self, dest: &mut impl std::io::Write) {
        dest.write(b"value from A");
    }
}

impl Evaluatable for B {
    
    fn evaluate(&self, dest: &mut impl std::io::Write) {
        dest.write(b"value from B");
    }
}

struct Expression {
    values: Vec<Box<dyn Evaluatable>>
}

impl Expression {

    fn evaluate(&self, dest: &mut impl std::io::Write) {
        self.values.iter().for_each(|e| e.evaluate(dest))
    }
}

fn test() -> std::io::Result<()> {

    let expr = Expression { values: vec![Box::new(A{}), Box::new(B{})]};

    //Write to a file:
    let file = std::io::BufWriter::new(std::fs::File::create_new("afile")?);
    expr.evaluate(&mut file);

    //Write to the memory
    let data = Vec::new();
    expr.evaluate(&mut data);

    Ok(())
}

我知道这是因为对象的安全性等,但如何实现这一点呢?可以建议使Write也成为一个dyn对象,并传递Write as**&mut dyn Write**,但调用一个虚方法为每个字节写不是我所希望的。什么是常见的方法来解决这个问题?

qvk1mo1f

qvk1mo1f1#

你可以使用一个保存trait对象的BufWriter,这会延迟对flushes的虚调用。

trait Evaluatable {
    fn evaluate(&self, dest: &mut BufWriter<&mut dyn std::io::Write>);
}

如果你必须用BufWriter做其他事情,这是不方便的,因为它现在有一个附加的生命周期,所以可能不适用于所有情况。其中一些可以通过使用BufWriter<Box<dyn Write>>来修复,但这是一个额外的分配。这也意味着使用不同类型的缓冲写入器的调用者必须将它 Package 在另一个缓冲区中。

相关问题