【发布时间】:2018-11-04 06:14:18
【问题描述】:
假设我有几个类似以下示例的结构,并且在next() 方法中我需要使用用户提供的缓冲区拉下一个事件,但如果此事件是注释,并且忽略 cmets 标志设置为是的,我需要再次拉下一个事件:
struct Parser {
ignore_comments: bool,
}
enum XmlEvent<'buf> {
Comment(&'buf str),
Other(&'buf str),
}
impl Parser {
fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
let result = loop {
buffer.clear();
let temp_event = self.parse_outside_tag(buffer);
match temp_event {
XmlEvent::Comment(_) if self.ignore_comments => {}
_ => break temp_event,
}
};
result
}
fn parse_outside_tag<'buf>(&mut self, _buffer: &'buf mut String) -> XmlEvent<'buf> {
unimplemented!()
}
}
但是,即使我启用了#![feature(nll)],此代码也会出现双重借用错误:
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:14:13
|
14 | buffer.clear();
| ^^^^^^ second mutable borrow occurs here
15 |
16 | let temp_event = self.parse_outside_tag(buffer);
| ------ first mutable borrow occurs here
|
note: borrowed value must be valid for the lifetime 'buf as defined on the method body at 12:5...
--> src/main.rs:12:5
|
12 | fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:16:53
|
16 | let temp_event = self.parse_outside_tag(buffer);
| ^^^^^^ mutable borrow starts here in previous iteration of loop
|
note: borrowed value must be valid for the lifetime 'buf as defined on the method body at 12:5...
--> src/main.rs:12:5
|
12 | fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
我可以(至少大约)理解为什么在关闭 NLL 功能的情况下会发生错误,但我不明白为什么会在 NLL 中发生。
无论如何,我的最终目标是在没有标志的情况下实现它,所以我也尝试过这样做(它是递归的,这真的很不幸,但我想出的所有非递归版本都无法在没有 NLL 的情况下工作):
fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
buffer.clear();
{
let temp_event = self.parse_outside_tag(buffer);
match temp_event {
XmlEvent::Comment(_) if self.ignore_comments => {}
_ => return temp_event,
}
}
self.next(buffer)
}
在这里,我尝试将借用限制在一个词法块内,并且该块中的 nothing 泄漏到外部。但是,我仍然收到错误消息:
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:23:19
|
15 | let temp_event = self.parse_outside_tag(buffer);
| ------ first mutable borrow occurs here
...
23 | self.next(buffer)
| ^^^^^^ second mutable borrow occurs here
24 | }
| - first borrow ends here
error: aborting due to previous error
同样,NLL 没有修复它。
我已经很久没有遇到我不理解的借用检查错误了,所以我希望它实际上是一些简单的东西,但由于某种原因我忽略了:)
我真的怀疑根本原因与显式的'buf 生命周期有关(特别是,打开 NLL 标志的错误有这些注释),但我不明白这里到底出了什么问题。
【问题讨论】:
-
您使用哪个
rustc版本?temp_event是/包含引用吗?我要的是rustc版本,因为match_default_bindings 最近稳定了,这可能会在此处作为参考结束,而您没想到它会成为参考。 -
@Tim rustc 版本是 2018-05-20 nightly 或最新稳定版。是的, temp_event 确实包含对缓冲区的引用。我认为它应该从方法签名中可见,但显然它不是:(我不确定该特定功能在这里是如何相关的,因为匹配没有捕获任何东西,它只是验证数据的结构。跨度>
-
这里有一个设计流程,因为
XmlEvent拥有buffer的所有权,当您选择返回temp_event时,您将其生命周期绑定到函数的生命周期。我认为没有办法解决这个问题。您可以在不构造XmlEvent的情况下进行检查。
标签: rust borrow-checker