I found that this is able to compile:
let x = &mut 10;
*x = 20;
This is very confusing. What are the semantics of mutably borrowing an literal?
I come from C++, where the compiler will definitely not allow me to refer to a rvalue like this:
int *x = &10;
int &y = 10;
Like C++, Rust has the concept of rvalues and lvalue. The reference calls them value expressions (rvalue) and place expressions (lvalue). Additionally, there are value contexts and place contexts (slots inside of expressions/statements where a value expression or place expression, respectively, is expected).
Rust has special rules for when a value expression (like a literal) is used in a place context (like the borrow operator &
). From the reference:
When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead [...].
So Rust automatically stores your value 10
in a memory location. The lifetime of the memory location varies depending on how the value expression is used, but in your case, the unnamed memory location has the same lifetime as the enclosing block. It thus is equivalent to a hidden let
binding:
let _compiler_generated = 10;
let x = &mut _compiler_generated;
*x = 20;
This doesn't just work with literals:
fn get_u32() -> u32 { 3 }
let x = &mut get_u32();
*x = 20;
While being confusing to those familiar with how lifetimes of objects work in languages like C++, this is a fairly useful feature in a few situations.
Related: if you use an immutable reference to a literal, the value is not just written to a stack slot, but into static memory. Meaning that let _: &'static u32 = &10
is valid! This has been specified in RFC 1414.