[英]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.