Assignment Statements
An assignment statement evaluates its right-hand side to a value and stores that value into the place named by its target (the target is a place, not merely a variable; see 5.2:2). If the target place currently holds a live (owned) value, that value is dropped before the new value is stored (overwrite-drop); storing into a moved-out place reinitializes it. The assignment itself evaluates to unit. These ownership effects are those of the core calculus's assign p = e form (docs/formal/01-core-calculus.md §5.2, §6.8) and of 3.8:55–56.
assign_stmt = assign_target "=" expression ";" ;
assign_target = IDENT { "." IDENT | "[" expression "]" }
| "self" ( "." IDENT | "[" expression "]" ) { "." IDENT | "[" expression "]" } ;
The assignment target is a place: a variable (or, inside a method, self) followed by any number of field (.f) and index ([e]) projections, freely mixed. All of x, p.f, arr[i], arr[i].f, p.arr[i], a.b.c, and o.items[i].arr[j] are valid targets. (Appendix A's place_expr is the normative statement of this production; see that appendix.)
Evaluation Order
In an assignment target = expression, the right-hand side expression is evaluated first to produce the value to be stored. The assignment target names a place; any index subexpressions appearing in the target (the [e] in an arr[e] target) are evaluated after the right-hand side, in source order (left-to-right). Once the place has been resolved, the produced value is written into it. This matches the core calculus's evaluation order: the assignment context assign p = E reduces the right-hand side E first, and the target place's index subexpressions are reduced as part of resolving the place for the store (docs/formal/01-core-calculus.md §6.2, §6.8).
fn tap(n: i32) -> i32 { @dbg(n); n }
fn main() -> i32 {
let mut arr: [i32; 4] = [0, 0, 0, 0];
// Prints 2 (the right-hand side) before 1 (the index of the place).
arr[tap(1)] = tap(2);
arr[1] // 2
}
Variable Assignment
The variable MUST have been declared with let mut.
The expression type MUST be compatible with the variable's type.
fn main() -> i32 {
let mut x = 0;
x = 42;
x
}
Array Element Assignment
Array element assignment requires a mutable array.
fn main() -> i32 {
let mut arr: [i32; 2] = [0, 0];
arr[0] = 20;
arr[1] = 22;
arr[0] + arr[1]
}
Struct Field Assignment
Struct field assignment requires a mutable struct value.
struct Point { x: i32, y: i32 }
fn main() -> i32 {
let mut p = Point { x: 0, y: 0 };
p.x = 42;
p.x
}
Nested Field Assignment
Fields of nested structs can be assigned through chained field access.
All struct values in the chain MUST be part of a mutable binding.
struct Inner { value: i32 }
struct Outer { inner: Inner }
fn main() -> i32 {
let mut o = Outer { inner: Inner { value: 0 } };
o.inner.value = 42;
o.inner.value
}
Assignment is Not an Expression
Assignment is a statement, not an expression. It MUST NOT be used in expression position.