Rust如何删除对临时值的不可变和可变引用?

imzjd6km  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(105)

首先,我知道有很多类似的问题,我读过很多讨论,但我仍然不明白我的情况是怎么回事。

struct Test {
    x: u32,
}

fn main() {
    let mut t = & mut Test { x: 0 };
    println!("{}", t.x);
    t = & mut Test { x: 1 };
    println!("{}", t.x);
}

好的,这会像预期的那样给出一个错误:

error[E0716]: temporary value dropped while borrowed
 --> src/main.rs:8:15
  |
8 |     t = & mut Test { x: 1 };
  |               ^^^^^^^^^^^^^- temporary value is freed at the end of this statement
  |               |
  |               creates a temporary value which is freed while still in use

creates a temporary value which is freed while still in use-这是正确的,但为什么这个错误不发生在之前?它只发生在&mut的第二次赋值上,而第一次赋值没有问题。它不应该也创建一个被丢弃的临时值吗?这就是我不明白的地方。
此外,如果我删除mut,那么一切都运行良好:

fn main() {
    let mut t = & Test { x: 0 };
    println!("{}", t.x);
    t = & Test { x: 1 };
    println!("{}", t.x);
}

但是为什么呢?一个不可变的引用仍然是一个引用,它仍然指向一些数据,临时值仍然被丢弃。所以引用应该是无效的。也应该给予错误,但不,它没有。为什么?为什么?
但是,等等,还有更多!如果我为Test实现Drop trait:

impl Drop for Test {
    fn drop(& mut self) { }
}

现在我又得到了同样的错误,而没有更改main()中的代码。有什么关系?

nszi6y05

nszi6y051#

为什么

let mut t = &mut Test { x: 0 };

works在Why is it legal to borrow a temporary?和参考文件中进行了描述:
let语句中表达式的临时作用域有时会扩展到包含let语句的块的作用域。当通常的临时作用域太小时,根据某些语法规则,可以这样做。

t = &mut Test { x: 1 };

不起作用,因为它不是let语句,因此没有资格获得相同的终身促销。

let mut t = &Test { x: 0 };

允许将临时提升为静态(因为它是不可变的),并且以下内容也符合常量提升的条件:

t = &Test { x: 1 };

这样就行了
由于Drop实现改变了静态变量和局部变量的语义,因此实现它的任何东西都不符合常量提升的条件,因此问题再次出现(对实现Drop的东西的引用只符合与可变引用相同的范围扩展)。链接的参考文章包含对所有这些的更全面的解释。

相关问题