下面的代码运行正常.

{
    let a = &mut 3;
    *a = 4;
    assert_eq!(*a, 4);
}

以下内容也适用.

{
    let a = Some(&3);
    let mut b = a.unwrap();
    assert_eq!(a.unwrap(), &3);
}

但以下内容无法编译.

{
    let a = Some(&mut 3);
    assert_eq!(*a.unwrap(), 3);
}

错误是:

40 |         let a = Some(&mut 3);
   |                           ^ - temporary value is freed at the end of this statement
   |                           |
   |                           creates a temporary which is freed while still in use
41 |         assert_eq!(*a.unwrap(), 3);
   |                     - borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

为什么Rust compiler对这些引用的处理方式不同,前两段代码可以使引用的生命周期 比临时的更长,而最后一段则不能?

推荐答案

这是Rust中一个叫做temporary lifetime extension的概念.不过,有一些规则可以控制临时工的生命周期 何时延长.它不会在任何时候发生临时借款;let语句右侧的表达式必须是所谓的"扩展表达式"上面链接的文件的这一部分清楚地解释了你问题中的第一个和第三个例子:

所以&mut 0(&1, &mut 2)Some { 0: &mut 3 }中的borrow 表达式都是扩展表达式.&0 + &1Some(&mut 0)中的借词不是:后者在语法上是一个函数调用表达式.

由于在第三个示例中分配给a的表达式不是扩展表达式,因此临时表达式的生存期不会扩展到let语句之外,这会导致生存期问题.

那么为什么这适用于Some(&3)呢?因为constant promotion:

当表达式可以写入常量并borrow 时,会将值表达式提升到'static槽,并且可以在最初写入表达式的位置取消引用该borrow ,而不会更改运行时行为.

由于borrow 是不可变的,Rust分配了一个隐藏的静态i32,并borrow 了它,得到了Option<&'static i32>,这显然对程序本身的整个生命周期都是有效的.从技术上讲,这不是临时的生命周期 延长,因为在i32提升为静态生命周期 后,它不再是临时的.

它基本上相当于这个(除了HIDDEN没有名字):

static HIDDEN: i32 = 3;
let a = Some(&HIDDEN);
let mut b = a.unwrap();
assert_eq!(a.unwrap(), &HIDDEN);

Rust相关问答推荐

trait声明中的生命周期参数

访问Rust中的隐藏变量

我怎样才能从一个Rust 的日期中go 掉3年?

如何装箱生命周期相关联的两个对象?

"value is never read警告似乎不正确.我应该忽略它吗?

原始数组数据类型的默认trait实现

在使用#[NO_STD]时,如何在Rust中收到紧急消息?

程序在频道RX上挂起

如何将带有嵌套borrow /NLL 的 Rust 代码提取到函数中

使用 Option 来分配?

Rust 文件未编译到 dll 中

Rust与_有何区别?

仅当函数写为闭包时才会出现生命周期错误

哪些特征通过 `Deref` 而哪些不通过?

为什么 i32 Box 类型可以在 Rust 中向下转换?

如何创建递归borrow 其父/创建者的 struct ?

LinkedList::drain_filter::drop 中 DropGuard 的作用是什么?

只有一个字符被读入作为词法分析器的输入

在使用大型表达式时(8k 行需要一小时编译),是否可以避免 Rust 中的二次编译时间?

如何在 Rust 的泛型函​​数中同时使用非拥有迭代器和消费迭代器?