[英]How to put a reference to a trait object in an Option?
我想在结构中的Option
中存储对io::Write
特征对象的引用,但我无法弄清楚如何。 我可以像这样直接放入引用:
pub struct Parameters<'a> {
pub log: &'a (io::Write + 'a),
// Other elements removed
}
然后从(例如)像这样的BufWriter
分配它:
let logstream = &BufWriter::new(f);
let parameters = Parameters {
log: logstream, // Other elements removed
};
这有效,但我希望logstream
是可选的。 如果我尝试:
pub struct Parameters<'a> {
pub log: Option<&'a(io::Write + 'a)>,
// Other elements removed
}
和
let logstream = match f {
Some(f) => Some(&BufWriter::new(f)),
None => None,
};
let parameters = Parameters {
log: logstream,
// Other elements removed
};
我明白了:
error[E0308]: mismatched types
--> src/main.rs:17:14
|
17 | log: logstream,
| ^^^^^^^^^ expected trait std::io::Write, found struct `std::io::BufWriter`
|
= note: expected type `std::option::Option<&dyn std::io::Write>`
found type `std::option::Option<&std::io::BufWriter<std::vec::Vec<u8>>>`
这里有什么合适的方法?
你必须以某种方式明确地用特征类型键入BufWriter
,并且你还必须更加小心一生。
这是一个如何工作的草图:
use std::io;
use std::io::BufWriter;
use std::str::from_utf8;
pub struct Parameters<'a> {
pub log: Option<&'a mut io::Write>,
// Other elements removed
}
fn main() {
let mut w = BufWriter::new(Vec::new());
let rw: &mut std::io::Write = &mut w;
let logstream = Some(rw);
let parameters = Parameters {
log: logstream,
// Other elements removed
};
parameters.log.unwrap().write(b"hello world").ok();
println!("{}", from_utf8(&w.into_inner().unwrap()).unwrap());
}
use std::io;
use std::io::BufWriter;
pub struct P<'a> {
pub log: Option<&'a mut io::Write>,
}
fn file() -> Option<Vec<u8>> {
Some(Vec::new())
}
fn main() {
let mut ow = file().map(|f| BufWriter::new(f));
let p = P {
log: ow.as_mut().map(|w| w as &mut io::Write),
};
p.log.unwrap().write(b"Hi!").ok();
println!(
"{}",
String::from_utf8(ow.unwrap().into_inner().unwrap()).unwrap()
);
}
而不是Option<W>
并尝试将其转换为Option<&mut io::Write>
,一步完成,分三步完成:
Option<W>
- > Option<io::BufWriter<W>>
来制作ow
。 这将是拥有BufWriter
的东西。 正如在另一个答案中所指出的,如果您尝试在模式匹配中创建BufWriter
然后立即对其进行引用,那么该引用的生命周期将限定在模式匹配的分支内,因此借用检查器将会抱怨。 as_mut()
从Option<io::BufWriter<W>>
为Option<&mut io::BufWriter<W>>
。 into
,但似乎没有一个实现,用于转换特征的实现者和特征对象的引用之间的转换。 在这个例子中, file()
返回一个Vec<u8>
作为底层Vec<u8>
,我这样做是为了使解决方案在Rust操场上可测试 ,但这也可以是一个File
。
最后,我删除了trait对象的生命周期约束,类型系统/借用检查器似乎认为没有必要。
感谢上面的答案。 在他们被发布之前,我自己有了一个想法并想出了这个(缩减到一个最小的例子,或多或少地显示我正在尝试做的事情):
use std::{env, process};
use std::fs::File;
use std::io::{self, BufWriter};
pub struct Parameters {
pub log: Option<Box<dyn io::Write>>,
}
fn main() {
let args: Vec<String> = env::args().collect();
let logfile = if args.len() > 1 {
Some(&args[1])
} else {
None
};
let logstream: Option<Box<dyn io::Write>> = match logfile {
Some(logfile) => {
let f = File::create(logfile).unwrap_or_else(|err| {
eprintln!("ERROR opening logfile: {}", err);
process::exit(1);
});
let logstream = BufWriter::new(f);
Some(Box::new(logstream))
}
None => {
None
},
};
let parameters = Parameters {
log: logstream,
};
play(parameters);
}
fn play(parameters: Parameters) {
// Rest of code removed
if let Some(mut stream) = parameters.log {
stream.write("Testing\n".as_bytes()).unwrap_or_else(|err| {
eprintln!("ERROR writing to logfile: {}", err);
process::exit(1);
});
}
}
这是一个很好的解决方案还是上面建议的更好?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.