The best example for “place expressions” are local variables. If you have
let x = String::from("Hello");
then the expression “x
” refers to the place x
. Simply writing x
in your code doesn’t do anything in particular to x
yet…
let x = String::from("Hello");
match x { _ => {} } // <- we wrote `x` here
println!("{x}"); // x ist still there. We also wrote `x` here by the way…
println!("{x}"); // x ist still there. Everything compiles.
We can use the place expression x
in many ways that won’t move x
. The most typical example is creating a reference, e.g. &x
. This will borrow x
, not move it. Similarly, the desugaring of println
only borrows x
, and a match
statement might borrow, borrow mutably, move, partially borrow or move, or even do nothing at all to the expression you pass to it, depending on what patterns you do or do not match against.
Now if we write
let y = x;
then x
gets moved. It’s not like “a move is attempted”, it’s more like “we definitely and quite explicitly move x
” here. And it’s the same thing with
let age = ages[0];
which explicitly moves ages[0]
. Just like x
above was a place expression of type String
, ages[0]
is a place expression of type Age
. We can borrow it or borrow it mutably to create &Age
or &mut Age
values via &ages[0]
or &mut ages[0]
. Unlike x
, we are not allowed to move ages[0]
though, since indexing in Rust doesn’t support by-move access at all. (Hence the error message. We do move, yet we are not allowed to.) This can happen for variables, too, but for different reasons. Typical examples of when you cannot access x: String
from the example above by-move include
When it’s borrowed
let x = String::from("Hello");
let r = &x; // borrows `x`
let y = x; // here’s the move
println!("{r}"); // r is still active until this point
Or when it’s no longer initialized
let x = String::from("Hello");
drop(x); // moves out of `x`
let y = x; // here’s the move
both examples above fail to compile, one with an error saying cannot move out of `x`…
and one use of moved value: `x`
. The former would still work if x
was accessed by mutable reference instead; the later can’t be borrowed either, and may only be accessed as the left-hand-side of an assignment that re-initializes the variables x = …new_value…;
.