我尝试实施log::Log
,以便对log()
的调用将消息附加到文件中。这是我的记录器:
pub struct MyLogger {
loglevel: LogLevelFilter,
logfile: Option<File>,
}
执行log :: Log:
impl Log for Logger {
fn enabled(&self, metadata: &LogMetadata) -> bool {
metadata.level() <= self.loglevel
}
fn log(&self, record: &LogRecord) {
if self.enabled(record.metadata()) {
let msg = format!("{}\t| {}\t| {}", record.level(), record.target(), record.args());
self.logfile.write_all(msg.as_bytes()).unwrap();
}
}
}
这是可以理解的,因为log()
没有采用可变引用,因此失败了。我不能采用可变参考,因为那样我就不能正确地实现这种类型,那么实现这一目标的惯用方法是什么?
答案 0 :(得分:3)
每当您需要提供不可变的界面但在幕后进行变异时,您可以使用内部可变性。这样做的常见方法是std::cell
。文档调出了这个特定的用例:
因为你必须使用变异来实现最初被定义为采取&amp; self的特征方法。
具体来说,在这种情况下我会尝试使用RefCell
。
不幸的是,Log
要求实施者也是Sync + Send
,但细胞不是。这意味着我们需要升级到可以处理多个线程的东西。那个东西是Mutex
:
extern crate log;
use std::fs::File;
use std::io::Write;
use std::sync::Mutex;
use log::{LogLevelFilter,LogMetadata,LogRecord,Log};
pub struct FileLogger {
loglevel: LogLevelFilter,
logfile: Option<Mutex<File>>,
}
impl Log for FileLogger {
fn enabled(&self, metadata: &LogMetadata) -> bool {
metadata.level() <= self.loglevel
}
fn log(&self, record: &LogRecord) {
if self.enabled(record.metadata()) {
let msg = format!("{}\t| {}\t| {}", record.level(), record.target(), record.args());
self.logfile.as_ref().map(|f| {
f.lock().unwrap().write_all(msg.as_bytes()).unwrap()
});
}
}
}
#[test]
fn it_works() {
}