我正在尝试使用quick-xml
封装XML解析器,该解析器在输入中包含一些特定的XML。主要代码如下:
pub struct GPXParser<B: BufRead> {
reader: Reader<B>,
buff: Vec<u8>,
}
impl<B> GPXParser<B> {
pub fn read_next<a>(&mut self) -> Result<XMLCache, Error> {
match self.reader.read_event(&mut self.buff) {
Ok(XMLEvent::Start(ref e)) if e.name() == b"wpt" => {
self.read_next_wpt() // --> Multiple mutable borrows error
}
_ => Err(Error::NoCaches),
}
}
fn read_next_wpt(&mut self) -> Result<XMLCache, Error> {
match self.reader.read_event(&mut self.buff) {
_ => Err(Error::NoCaches),
}
}
}
然后我在rust-lang.org上阅读了这个topic,并提到:
惯用的Rust代码通常避免持有对可变对象内部的长期引用,并支持使用不可变引用或独立值的替代方法
我尝试使用中间buff
元素更改我的方法:
pub struct GPXParser<B: BufRead> {
reader: Reader<B>,
}
impl<B> GPXParser<B> {
pub fn read_next<a>(&mut self) -> Result<XMLCache, Error> {
let mut buff: Vec<u8> = Vec::new();
match self.reader.read_event(&mut buff) {
Ok(XMLEvent::Start(ref e)) if e.name() == b"wpt" => {
self.read_next_wpt(&mut buff) // --> Multiple mutable borrows error
}
_ => Err(Error::NoCaches),
}
}
fn read_next_wpt(&mut self, buff: &mut Vec<u8>) -> Result<XMLCache, Error> {
match self.reader.read_event(buff) {
_ => Err(Error::NoCaches),
}
}
}
我没有改变方法。
我试图将match
语句拆分为两行:
pub fn read_next<a>(&mut self) -> Result<XMLCache, Error> {
let result = self.reader.read_event(&mut self.buff);
match result {
Ok(XMLEvent::Start(ref e)) if e.name() == b"wpt" => self.read_next_wpt(),
_ => Err(Error::NoCaches),
}
}
但是我得到了同样的错误:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/gpx/mod.rs:34:17
|
31 | let result = self.reader.read_event(&mut self.buff);
| --------- first mutable borrow occurs here
...
34 | self.read_next_wpt()
| ^^^^ second mutable borrow occurs here
...
39 | }
| - first borrow ends here
有没有办法在不同的方法调用周围使用相同的缓冲区?
游戏中是否会有一些生命周期?
如果没有,那么解决这个问题的惯用Rust方法是什么?
答案 0 :(得分:1)
问题来自prototype for read_event中的'b
生命周期:
pub fn read_event<'a, 'b>(
&'a mut self,
buf: &'b mut Vec<u8>
) -> Result<Event<'b>>
这会将缓冲区的生命周期与返回值的生命周期相关联,因此只要结果处于活动状态,就无法重复使用缓冲区。只有在你完成使用结果之后,当你不想要递归和递归时,你可以通过尽早返回来解决它:
pub fn read_next<a>(&mut self) -> Result<XMLCache, Error> {
match self.reader.read_event(&mut self.buff) {
Ok(XMLEvent::Start(ref e)) if e.name() == b"wpt" => (),
_ => { return Err(Error::NoCaches) },
}
self.read_next_wpt()
}
如果您想添加更多案例,您必须首先从结果中提取您想要使用的任何相关信息,包括选择要调用的方法所需的任何信息,然后在调用方法之前将结果超出范围。例如:
pub fn read_next<a>(&mut self) -> Result<XMLCache, Error> {
let next_method = match self.reader.read_event(&mut self.buff) {
Ok(XMLEvent::Start(ref e)) if e.name() == b"wpt" => GPXParser<B>::read_next_wpt,
Ok(XMLEvent::Start(ref e)) if e.name() == b"foo" => GPXParser<B>::read_next_foo,
_ => { return Err(Error::NoCaches) },
}
next_method(self)
}
或者,如果性能影响小到可以接受,那么每次使用不同的缓冲区可能会更容易(你应该测量它以备份你的决定)。
以下原始答案供参考:
尝试将read_event
和匹配分成不同的行:
let result = self.reader.read_event(&mut self.buff);
match result {
...
}
你的问题是缓冲区是为整个匹配表达式可靠地借用的,所以你不能在匹配组内重新借用缓冲区。通过将代码分成两行,缓冲区仅用于第一个表达式(let result=...
),并且可以在匹配中再次借用。
将来,当非词汇生命稳定时,这可能会被修复。