gpt4 book ai didi

rust - 使用可变引用覆盖变量时借用检查器错误

转载 作者:行者123 更新时间:2023-12-04 14:59:21 26 4
gpt4 key购买 nike

我有一个结构 UI 持有对 Stdout 的可变引用。与其在更新时改变它,不如用全新的 UI 替换它:

use std::io::{stdout, Result, Stdout, Write};

struct UI<'s> {
stdout: &'s mut Stdout,
v: Box<()>, // If remove this field, the error goes away.
}

impl<'s> UI<'s> {
fn new(stdout: &'s mut Stdout) -> Result<Self> {
let ui = UI {
stdout: stdout,
v: Box::new(()),
};

Ok(ui)
}

fn write(&mut self) -> Result<()> {
write!(self.stdout, "heyyyyy")?;
self.stdout.flush()?;

Ok(())
}
}

fn main() -> Result<()> {
let mut stdout = stdout();
let mut ui = UI::new(&mut stdout)?;

ui = UI::new(&mut stdout)?;
ui.write()?; // If you comment this line out, the error goes away.

Ok(())
}

playground

借用检查器提示 stdout 被可变地借用了两次:

error[E0499]: cannot borrow `stdout` as mutable more than once at a time
--> src/main.rs:30:18
|
28 | let mut ui = UI::new(&mut stdout)?;
| ----------- first mutable borrow occurs here
29 |
30 | ui = UI::new(&mut stdout)?;
| -- ^^^^^^^^^^^ second mutable borrow occurs here
| |
| first borrow might be used here, when `ui` is dropped and runs the destructor for type `UI<'_>`

有两个奇怪的行为:

  1. 如果我删除字段 v,错误就会消失。
  2. 如果我删除 ui.display()?,错误也会消失。

这里有什么问题?

寻址 @kmdreko's suggestion :

The first point is explained in the error message, albeit in a roundabout way if you don't know what's going on. Box implements Drop, so that it can deallocate its contents when destroyed; and therefore UI automatically implements Drop, which means there is code executed which could access stdout between reborrowing it for a new UI and assigning it to ui.

那为什么会返回错误呢?

fn main() -> Result<()> {
let mut stdout = stdout();
let mut ui = UI::new(&mut stdout)?;

for _ in 0..10 {
drop(ui);

ui = UI::new(&mut stdout)?;
ui.write()?;
}

Ok(())
}
error[E0499]: cannot borrow `stdout` as mutable more than once at a time
--> src/main.rs:33:22
|
28 | let mut ui = UI::new(&mut stdout)?;
| ----------- first mutable borrow occurs here
...
33 | ui = UI::new(&mut stdout)?;
| -- ^^^^^^^^^^^ second mutable borrow occurs here
| |
| first borrow might be used here, when `ui` is dropped and runs the destructor for type `UI<'_>`

Someone on Reddit建议为 UI 实现 take(self) -> &'s mut Stdout 并且它有效,但我不知道为什么。 Playground .

最佳答案

替换值时,必须先创建新值:

struct Noisy(u8);

impl Noisy {
fn new(v: u8) -> Self {
eprintln!("creating {}", v);
Self(v)
}
}

impl Drop for Noisy {
fn drop(&mut self) {
eprintln!("dropping {}", self.0);
}
}

fn main() {
let mut ui = Noisy::new(1);
ui = Noisy::new(2);
}
creating 1
creating 2
dropping 1
dropping 2

这意味着您的两个 UI 结构将尝试共存。由于它们都有对 stdout 的可变引用,因此 Drop::drop 实现可能改变 stdout,这将违反引用规则,因为在一处会有多个事件的可变引用。

当您不调用write 时,非词法借用检查器会发现不需要借用,所以没有问题。

Then why does [explicitly dropping the value before reassigning it] return an error?

因为那是a limitation of the current borrow checker implementation .

另见:

关于rust - 使用可变引用覆盖变量时借用检查器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67258782/

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