我有一个简单的结构
Parser
pub struct Parser {
pos: usize,
input: String,
}
我正在尝试构建一个 Markdown 解析器,并且有一个方法
parse_md_line
包含一个 while 循环,我试图根据 delimiter
值 使 while 循环的条件动态化
pub fn parse_md_line(&mut self, delimiter: Option<char>) -> String {
let mut result = String::new();
let mut cond: Box<dyn Fn() -> bool> = Box::new(|| {
return self.pos < self.input.len()
&& (self.next_char() != '\n' || utils::is_whitespace(self.next_char()));
});
if delimiter.is_some() {
cond = Box::new(|| {
return self.pos < self.input.len() && self.next_char() != delimiter.unwrap();
});
}
while cond() {
let normal_text = self.parse_alpha_numeric(true); // this mutates `self`
.....
}
result
}
while循环的内部工作是隐藏的,因为它们确实很重要,但它调用了一些方法,这会改变
self
。
此代码会引发
let normal_text = self.parse_alpha_numeric(true);
错误,
**不能借用 *self 作为可变的,因为它也是借用为不可变的。
我了解该错误及其发生原因。但无法找到解决问题的方法。我敲了一下并尝试使用
RefCell
,Rc
仍然没有用。
也许可以使用
RefCell
来完成,根据我的尝试,代码变得不必要的复杂。
有没有标准或更干净的方法来处理这样的事情。
这里有多个问题:
Fn
无法修改它的环境,你可以将其更改为FnMut
但是&mut self
只能保存一次self
,而闭包保留独占引用,但您无法创建对 self 的多个独占引用。要解决这些问题,您可以将
self
作为闭包的参数,这样它就不需要捕获 self
,它也不需要是 FnMut
,因为您不需要修改任何环境更长:
pub fn parse_md_line(&mut self, delimiter: Option<char>)
let cond: Box<dyn Fn(&mut Self) -> bool> = if delimiter.is_some() {
Box::new(|this| {
return this.pos < this.input.len() && this.next_char() != delimiter.unwrap();
})
} else {
Box::new(|this| {
return this.pos < this.input.len()
&& (this.next_char() != '\n' || this.next_char().is_whitespace());
})
};
while cond(self) {
let _normal_text = self.parse_alpha_numeric(true); // this mutates `self`
}
}