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!");
}