我有一个用例,我只想解析文件的开头直到我决定停止解析。这可以是 4kB 或更多。确切金额尚不清楚。因此无需读取整个文件(例如可以是 100kB)。
我在最常用的名为“nom”的解析器组合器箱中看到的所有内容是,总是解析内存中完整的整块字节或字符。
构建一个动态从文件中读取的自己的数据结构的想法效果不佳,因为我无法覆盖不可变的自引用,如下所示:
struct MyInput {
pb : PathBuf,
read : Box::<dyn Read>,
filelength : u64,
current_content : String,
}
impl MyInput {
fn new( pb : PathBuf) -> Self{
let file = OpenOptions::new().read(true).open(pb.clone()).unwrap();
let filelength = std::fs::metadata(pb.clone()).unwrap().len();
let current_content = "".to_string();
Self { pb, read : Box::new( file), filelength, current_content}
}
}
impl InputLength for MyInput {
fn input_len(&self) -> usize {
self.filelength as usize // here I have to tweake something later because char vs. u8
}
}
// here lies the problem
impl Compare<&str> for MyInput {
fn compare(&self, t: &str) -> nom::CompareResult {
// I cannot fill a cache as I indended to do in self.current_content
// because &self is immutable
todo!()
}
fn compare_no_case(&self, t: &str) -> nom::CompareResult {
todo!()
}
}
我的问题还有其他解决方案吗?
我不认为这应该是你的首选解决方案,但是如果你想改变
self
,并且特征的接口只给你一个&self
,你可以使用内部可变性模式。例如RefCell
。请阅读本书中的详细解释以了解更多信息。但对于快速片段,您可以使用它。请注意,这会增加跟踪 RefCell
引用数量的少量运行时开销。
use std::cell::RefCell;
use std::ops::DerefMut;
struct Inner {
pb : PathBuf,
read : Box::<dyn Read>,
filelength : u64,
current_content : String,
}
struct MyInput {
inner: RefCell<Inner>,
}
impl Compare<&str> for MyInput {
fn compare(&self, t: &str) -> nom::CompareResult {
// The call to deref_mut is only to show that you can obtain
// a mutable reference to inner.
let inner: &mut Inner = self.inner.borrow_mut().deref_mut();
todo!();
}
}