我发现这段代码可以编译通过:
let x = &mut 10;
*x = 20;
这很令人困惑。借用字面值的可变语义是什么?
我来自C++,在那里编译器绝对不会允许我像这样引用右值:
int *x = &10;
int &y = 10;
let x = &mut 10;
*x = 20;
这很令人困惑。借用字面值的可变语义是什么?
我来自C++,在那里编译器绝对不会允许我像这样引用右值:
int *x = &10;
int &y = 10;
和 C++ 一样,Rust 也有 rvalue 和 lvalue 的概念。Rust 的引用称它们为 value expressions(rvalue)和 place expressions(lvalue)。此外,还有 value contexts 和 place 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中进行了说明。
const T &x = get_value();
也可以扩展为 const T &&x = get_value();
,据说也是可行的! - Veedrac