在Rust中,可变地借用字面量的语义是什么?

6
我发现这段代码可以编译通过:
let x = &mut 10;
*x = 20;

这很令人困惑。借用字面值的可变语义是什么?

我来自C++,在那里编译器绝对不会允许我像这样引用右值:

int *x = &10;
int &y = 10;

@Boiethios 我不认为这是重复的。它们是相关的,绝对没错。但问题是不同的。 - Lukas Kalbertodt
2
有趣的是,在C语言中,这个 `#include <stdio.h>int main(void) { int *p = &(int){ 10 }; *p = 20; printf("%d", *p); }` 是被允许的。 - Stargateur
1个回答

11

和 C++ 一样,Rust 也有 rvalue 和 lvalue 的概念。Rust 的引用称它们为 value expressions(rvalue)和 place expressions(lvalue)。此外,还有 value contextsplace contexts(表达式/语句中期望出现值表达式或位置表达式的插槽)。

Rust 对于在位置上下文中使用值表达式(如借用运算符 &)有特殊规则。参见文档

在大多数位置表达式上下文中使用值表达式时,会创建一个未命名的临时内存位置,并将其初始化为该值,然后表达式将计算为该位置[...]。

因此,Rust 自动将您的值 10 存储在内存位置中。内存位置的生命周期取决于值表达式的使用方式,但在本例中,未命名的内存位置与封闭块的生命周期相同。因此,它等效于一个隐藏的 let 绑定:

let _compiler_generated = 10;
let x = &mut _compiler_generated;
*x = 20;

这不仅适用于文字字面量:

fn get_u32() -> u32 { 3 }

let x = &mut get_u32();
*x = 20;

虽然这对于那些熟悉诸如C++等语言中对象生命周期工作方式的人来说可能很困惑,但在某些情况下,这是一个相当有用的功能。


相关的:如果您使用一个不可变引用指向字面量,该值不仅会被写入堆栈位置,而且会被写入静态内存。这意味着let _: &'static u32 = &10是有效的!这已经在RFC 1414中进行了说明。


1
C++ 有时也会做类似的事情,尽管规则略有不同。 - Veedrac
1
@Veedrac 我只能想到当const引用被传递给函数时的特殊规则(这将使引用持续到函数调用的持续时间)。还有更多的规则吗? - Lukas Kalbertodt
1
const T &x = get_value(); 也可以扩展为 const T &&x = get_value();,据说也是可行的! - Veedrac
这个也记录了此处描述的行为。 - perrocallcenter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接