对已经可变引用的对象保持读写控制的最佳“Rust”方法是什么?

问题描述 投票:0回答:1

假设我想测试一个结构体 (

Consumer
) 的行为,该结构体采用对另一个结构体 (
Target
) 的可变引用。测试其正确性的唯一方法是获得对
Target
的直接读写访问。我们保证这里没有多线程。

我想到了类似下面的内容,尽管由于明显违反借用规则而无法编译:

t
仍然可变地借用,而我们稍后想再次借用它。

use std::io::Write;

struct Consumer<'a, W: Write> {
    out: &'a mut W
}

impl<'a, W: Write> Consumer<'a, W> {
    pub fn consume(&mut self, data: &[u8]) {
        // do something else
        self.out.write(data).unwrap();
    }
}

struct Target {
    buf: Vec<u8>
}

impl Target {
    pub fn drain(&mut self) {
        self.buf.clear();
    }
}

impl Write for Target {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.buf.extend_from_slice(buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

mod tests {
    use crate::{Target, Consumer};

    #[test]
    fn test_that_consumes_ok() {
        let mut t = Target{ buf: Vec::new() };
        let mut c = Consumer{ out: &mut t };
        c.consume(b"hello");
        c.consume(b"world");

        // error in this line:
        assert_eq!(t.buf.as_slice(), b"helloworld");

        // also error:
        t.drain();

        c.consume(b"new");
        assert_eq!(t.buf.as_slice(), b"new");
    }
}


fn main() {}

所以问题不是关于这种测试方法本身(这是有问题的),而是关于如何在没有防弹

Arc<Mutex>
方式的情况下提供对多个地方的可变引用。直觉上我明白像
Rc<RefCell>
这样的东西会有帮助,但无法构建它。请帮忙。

rust borrow-checker
1个回答
0
投票

为了补充 cafce25 的评论,并且要明确的是,仅仅因为没有多线程并不意味着 R|W 不安全:对于所有编译器从外部知道的

Consumer
保留对
out
内容的引用,写入可能会使其无效。这是一个问题,例如std:C++ 中的向量。

这里你有多种方法来处理这个问题:

  • 执行此操作的“公共”方法是使

    Consumer
    生成对其包含的
    target
    的子引用。这是一个足够常见的模式,您可以使用
    BufWriter::get_mut
    来查看它,它允许获取底层编写器的句柄。

  • 但是因为

    Consumer
    是完全开放的(因为您可以使用结构文字构造它),所以您实际上可以在这里访问它:

    让 t = &mut *c.out;

应该可以正常工作。

© www.soinside.com 2019 - 2024. All rights reserved.