假设我想测试一个结构体 (
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>
这样的东西会有帮助,但无法构建它。请帮忙。
为了补充 cafce25 的评论,并且要明确的是,仅仅因为没有多线程并不意味着 R|W 不安全:对于所有编译器从外部知道的
Consumer
保留对 out
内容的引用,写入可能会使其无效。这是一个问题,例如std:C++ 中的向量。
这里你有多种方法来处理这个问题:
执行此操作的“公共”方法是使
Consumer
生成对其包含的 target
的子引用。这是一个足够常见的模式,您可以使用 BufWriter::get_mut
来查看它,它允许获取底层编写器的句柄。
但是因为
Consumer
是完全开放的(因为您可以使用结构文字构造它),所以您实际上可以在这里访问它:
让 t = &mut *c.out;
应该可以正常工作。