Rust 即使NLL打开,循环中也会发生双可变借用错误
假设我有以下示例中的几种结构,在Rust 即使NLL打开,循环中也会发生双可变借用错误,rust,borrow-checker,Rust,Borrow Checker,假设我有以下示例中的几种结构,在next()方法中,我需要使用用户提供的缓冲区拉取下一个事件,但是如果此事件是注释,并且ignore comments标志设置为true,我需要再次拉取下一个事件: struct Parser { ignore_comments: bool, } enum XmlEvent<'buf> { Comment(&'buf str), Other(&'buf str), } impl Parser { fn
next()
方法中,我需要使用用户提供的缓冲区拉取下一个事件,但是如果此事件是注释,并且ignore comments标志设置为true,我需要再次拉取下一个事件:
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!()
}
}
我可以(至少大概)理解为什么在NLL功能关闭的情况下会发生错误,但我不理解为什么在NLL中会发生错误
无论如何,我的最终目标是在没有标志的情况下实现它,所以我也尝试过这样做(它是递归的,这真的很不幸,但是我提出的所有非递归版本都不可能在没有NLL的情况下工作):
再说一次,NLL并没有解决这个问题
很长一段时间以来,我一直没有遇到我不理解的借阅检查错误,所以我希望这实际上是一个简单的问题,因为某种原因我忽略了:)
我真的怀疑根本原因与显式的'buf
生存期有关(特别是,打开NLL标志的错误有这些注释),但我不明白这里到底出了什么问题。这一点可以通过这种简化的情况来说明:
fn next<'buf>(buffer: &'buf mut String) -> &'buf str {
loop {
let event = parse(buffer);
if true {
return event;
}
}
}
fn parse<'buf>(_buffer: &'buf mut String) -> &'buf str {
unimplemented!()
}
fn main() {}
RUSTFLAGS=“-Zpolonius”货物+夜间建造
因为这是跨函数的,所以有时可以通过内联函数来解决这个问题。我发布了一个问题(),这个问题的答案回答了这个问题 我将在这里记录一个解决方案,它也回答了这个问题。假设您有这样的代码,只使用钋编译:
struct Inner;
enum State<'a> {
One,
Two(&'a ()),
}
fn get<'s>(_inner: &'s mut Inner) -> State<'s> {
unimplemented!()
}
struct Outer {
inner: Inner,
}
impl Outer {
pub fn read<'s>(&'s mut self) -> &'s () {
loop {
match get(&mut self.inner) {
State::One => (), // In this case nothing happens, the borrow should end and the loop should continue
State::Two(a) => return a, // self.inner ought to be borrowed for 's, that's just to be expected
}
}
}
}
您使用哪个
rustc
版本?temp\u事件是否为/包含引用?我要的是rustc
版本,因为它最近稳定了下来,这可能会在这里以引用结束,而你没想到它会是引用。@Tim rustc版本是2018-05-20 nightly或最新的稳定版本。是的,temp_事件确实包含对缓冲区的引用。我认为它应该从方法签名中可见,但显然不是:(我不确定这一特定功能在这里是如何关联的,因为匹配没有捕获任何东西,它只是验证数据的结构。这里有一个设计流程,当您选择返回temp_event
时,XmlEvent
拥有buffer
的所有权,您将它的生存期绑定到函数的生存期。我想没有办法解决这个问题。你可以不用构造XmlEvent
来进行检查。感谢你和Niko一起检查这个问题!我想现在我必须坚持safe
来克服这个问题。我想我知道如何克服它,而不必诉诸safe
,但它需要改变内部方法我不喜欢的od类型:(
struct Inner;
enum State<'a> {
One,
Two(&'a ()),
}
fn get<'s>(_inner: &'s mut Inner) -> State<'s> {
unimplemented!()
}
struct Outer {
inner: Inner,
}
impl Outer {
pub fn read<'s>(&'s mut self) -> &'s () {
loop {
match get(&mut self.inner) {
State::One => (), // In this case nothing happens, the borrow should end and the loop should continue
State::Two(a) => return a, // self.inner ought to be borrowed for 's, that's just to be expected
}
}
}
}
struct Inner;
enum State<'a> {
One,
Two(&'a ()),
}
fn get<'s>(_inner: &'s mut Inner) -> State<'s> {
unimplemented!()
}
struct Outer {
inner: Inner,
}
impl Outer {
pub fn read<'s>(&'s mut self) -> &'s () {
loop {
match get(&mut self.inner) {
State::One => (), // In this case nothing happens, the borrow should end and the loop should continue
State::Two(a) => {
return match get(&mut self.inner) { // Borrowing again compiles!
State::Two(a) => a,
_ => unreachable!(),
}
}, // self.inner ought to be borrowed for 's, that's just to be expected
}
}
}
}
fn main() {
println!("Hello, world!");
}