gpt4 book ai didi

Using a closure as while loop condition in struct's method which requires a reference to self, in Rust(在结构的方法中使用闭包作为While循环条件,该条件需要引用Rust中的self)

转载 作者:bug小助手 更新时间:2023-10-25 21:37:28 31 4
gpt4 key购买 nike



I have a simple struct Parser

我有一个简单的结构解析器


pub struct Parser {
pos: usize,
input: String,
}

I'm trying to build a markdown parser and there's a method parse_md_line which contains a while loop and I'm trying to make the while loop's condition dynamic based on delimiter value

我正在尝试构建一个markdown解析器,并且有一个包含While循环的方法parse_md_line,并且我正在尝试根据分隔符值动态设置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 loop's inner working are hidden as they do matter much, but it calls some methods, which mutates self.

虽然循环的内部工作是隐藏的,因为它们确实很重要,但它调用了一些方法,这会使自身发生突变。


This code throw error for let normal_text = self.parse_alpha_numeric(true);,
**cannot borrow *self as mutable because it is also borrowed as immutable.

此代码引发错误,因为let Normal_Text=self.parse_Alpha_Numeric(True);,**不能借用*self作为可变对象,因为它也被借用为不可变对象。


I understand the error and why it's happening. But cannot figure out a way to work it out. I hit and tried using RefCell, Rc still nothing of use.

我理解这个错误以及为什么会发生这种情况。但想不出办法来解决这个问题。我点击并尝试使用Refcell,RC仍然没有任何用处。


Maybe It can be done using RefCell, from what I've tried the code grew unnecessary complex.

也许这可以使用RefCell来完成,从我尝试的情况来看,代码变得不必要的复杂。


Is there a standard or cleaner way to handle things like this.

有没有一个标准的或更干净的方法来处理这样的事情。


更多回答
优秀答案推荐

Multiple issues here:

这里有多个问题:



  1. Fn can't modify it's environment, you could change it to FnMut but

  2. you're creating multiple closures that want to hold a mutable reference to self simultaneously but &mut self can only be held once

  3. you want to modify self while the closure holds on to a exclusive reference, you can't create multiple exclusive references to self though.


To solve them you can make self a parameter for the closure, that way it doesn't need to capture self, or hold on to it across the loop body, it also doesn't need to be a FnMut because you don't modify the environment any longer:

要解决这些问题,可以将self作为闭包的参数,这样它就不需要捕获self,或者在循环体中保留它,它也不需要是FnMut,因为您不再修改环境:


pub fn parse_md_line(&mut self, delimiter: Option<char>) {
let cond: Box<dyn Fn(&mut Self) -> bool> = if let Some(delimiter) = delimiter {
Box::new(move |this| this.pos < this.input.len() && this.next_char() != delimiter)
} else {
Box::new(|this| this.pos < this.input.len() && !this.next_char().is_whitespace())
};
while cond(self) {
let _normal_text = self.parse_alpha_numeric(true); // this mutates `self`
}
}

You can also just write the condition inline to avoid any allocation of a closure and the complete problem, the compiler is clever enough to optimize the if check to ahead of the loop:

您也可以只内联编写条件,以避免任何闭包和完整问题的分配,编译器足够聪明,可以在循环之前优化if检查:


pub fn parse_md_line(&mut self, delimiter: Option<char>) {
while self.pos < self.input.len()
&& if let Some(delimiter) = delimiter {
self.next_char() != delimiter
} else {
!self.next_char().is_whitespace()
}
{
let _normal_text = self.parse_alpha_numeric(true); // this mutates `self`
}
}


Alternatively, you can avoid using methods of Self in the closure.

或者,您可以避免在闭包中使用self方法。


pub fn parse_md_line(&mut self, delimiter: Option<char>) -> String {
let mut result = String::new();
let mut check_delimiter: Box<dyn Fn(char) -> bool> = match delimiter {
Some(delimiter) => Box::new(move |c| {
c != delimiter
}),
None => Box::new(|c| {
c != '\n' /* || utils::is_whitespace(self.next_char()) */
})
};
while self.pos < self.input.len() && check_delimiter(self.next_char()) {
let _normal_text = self.parse_alpha_numeric(true);
}
result
}

Also, with such an approach, you can avoid using the .unwrap() in the code.
playground link.

此外,使用这种方法,您可以避免在代码中使用.unwork()。操场链接。


更多回答

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com