gpt4 book ai didi

rust - 即使 NLL 打开,循环中的双可变借用错误也会发生

转载 作者:行者123 更新时间:2023-11-29 07:44:32 26 4
gpt4 key购买 nike

假设我有如下示例中的几个结构,并且在 next() 方法中我需要使用用户提供的缓冲区提取下一个事件,但是如果此事件是注释,并忽略评论标志设置为真,我需要再次拉下一个事件:

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)
}

在这里,我试图将借用限制在词法 block 内,没有从这个 block 泄漏到外部。但是,我仍然收到错误消息:

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 标志的错误有这些注释),但我无法理解这里到底出了什么问题。

最佳答案

这是 a limitation of the current implementationnon-lexical lifetimes这可以用这个简化的案例来证明:

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() {}

此限制可防止 NLL case #3 : 跨函数的条件控制流

在编译器开发人员的术语中,非词法生命周期的当前实现是“位置不敏感”的。位置敏感度最初可用,但以性能的名义被禁用。

I asked Niko Matsakis about this code :

In the context of your example: the value event only has to have the lifetime 'buf conditionally — at the return point which may or may not execute. But when we are "location insensitive", we just track the lifetime that event must have anywhere, without considering where that lifetime must hold. In this case, that means we make it hold everywhere, which is why you get a compilation failure.

One subtle thing is that the current analysis is location sensitive in one respect — where the borrow takes place. The length of the borrow is not.

好消息是,将位置敏感度的概念添加回来被视为对非词汇生命周期实现的增强。坏消息:

That may or may not be before the [Rust 2018] edition.

(注意:它没有进入 Rust 2018 的初始版本)

这取决于(甚至是更新的!)提高性能的非词汇生命周期的底层实现。您可以使用 -Z polonius 选择加入这个半实现的版本:

rustc +nightly -Zpolonius --edition=2018 example.rs
RUSTFLAGS="-Zpolonius" cargo +nightly build

因为这是跨函数,有时您可以通过内联函数来解决这个问题。

关于rust - 即使 NLL 打开,循环中的双可变借用错误也会发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50519147/

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