TL;DR:我想实现std::io::Write输出到内存缓冲区的特征,最好是字符串,用于单元测试目的。
我一定错过了一些简单的东西。
与另一个问题类似,在 Rust 中写入文件或标准输出,我正在编写可以与任何std::io::Write实现一起使用的代码。
它在如下定义的结构上运行:
pub struct MyStructure {
writer: Box<dyn Write>,
}
Run Code Online (Sandbox Code Playgroud)
现在,很容易创建实例写入文件或stdout:
impl MyStructure {
pub fn use_stdout() -> Self {
let writer = Box::new(std::io::stdout());
MyStructure { writer }
}
pub fn use_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let writer = Box::new(File::create(path)?);
Ok(MyStructure { writer })
}
pub fn printit(&mut self) -> Result<()> {
self.writer.write(b"hello")?;
Ok(())
}
}
Run Code Online (Sandbox Code Playgroud)
但是对于单元测试,我还需要有一种方法来运行业务逻辑(这里用 method 表示printit())并捕获其输出,以便在测试中可以检查其内容。
我无法弄清楚如何实现这一点。这个操场代码显示了我想如何使用它,但它没有编译,因为它违反了借用规则。
// invalid code - does not compile!
fn main() {
let mut buf = Vec::new(); // This buffer should receive output
let mut x2 = MyStructure { writer: Box::new(buf) };
x2.printit().unwrap();
// now, get the collected output
let output = std::str::from_utf8(buf.as_slice()).unwrap().to_string();
// here I want to analyze the output, for instance in unit-test asserts
println!("Output to string was {}", output);
}
Run Code Online (Sandbox Code Playgroud)
知道如何正确编写代码吗?即,如何在之后可以访问的内存结构(String,Vec,...)之上实现编写器?
像这样的东西确实有效:
let mut buf = Vec::new();
{
// Use the buffer by a mutable reference
//
// Also, we're doing it inside another scope
// to help the borrow checker
let mut x2 = MyStructure { writer: Box::new(&mut buf) };
x2.printit().unwrap();
}
let output = std::str::from_utf8(buf.as_slice()).unwrap().to_string();
println!("Output to string was {}", output);
Run Code Online (Sandbox Code Playgroud)
但是,为了使其工作,您需要修改您的类型并添加一个生命周期参数:
pub struct MyStructure<'a> {
writer: Box<dyn Write + 'a>,
}
Run Code Online (Sandbox Code Playgroud)
请注意,在您的情况下(您省略了+ 'a部分),编译器假定您将其'static用作 trait 对象的生命周期:
// Same as your original variant
pub struct MyStructure {
writer: Box<dyn Write + 'static>
}
Run Code Online (Sandbox Code Playgroud)
这限制了可以在这里使用的类型集,特别是,您不能使用任何类型的借用引用。因此,为了获得最大的通用性,我们必须在这里明确并定义生命周期参数。
另请注意,根据您的用例,您可以使用泛型而不是特征对象:
pub struct MyStructure<W: Write> {
writer: W
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,类型在程序的任何点都是完全可见的,因此不需要额外的生命周期注释。
| 归档时间: |
|
| 查看次数: |
1394 次 |
| 最近记录: |