Mutability of Structs
For a simple value like an int, the choice between let and var only decides whether the variable can be reassigned. For a struct it decides more: because a struct is a value type, the binding that holds it governs every field. Mutability is deep — there is no way to have an immutable struct with mutable fields, or the reverse.
struct Point {
x: float64;
y: float64;
}let — Fully Immutable
A struct bound with let cannot be reassigned, and none of its fields can be modified:
let a = Point { x: 1.0, y: 1.0 };
a = Point { x: 0.0, y: 0.0 }; // error: cannot reassign a let binding
a.x = 2.0; // error: cannot modify a field of an immutable structvar — Fields and Whole Value Both Mutable
A struct bound with var allows both field-level writes and whole-value reassignment:
var b = Point { x: 0.0, y: 0.0 };
b.x = 3.0; // modify one field
b.y = 4.0;
b = Point { x: 1.0, y: 1.0 }; // or replace the entire valueNested Structs
The rule applies through nesting: a field that is itself a struct is mutable only when the top-level binding is var. There is no per-field opt-in or opt-out.
struct Line {
start: Point;
end: Point;
}
var line = Line {
start: Point { x: 0.0, y: 0.0 },
end: Point { x: 1.0, y: 1.0 },
};
line.start.x = 5.0; // OK — reached through a var bindingIf line were a let, line.start.x = 5.0 would be rejected just like a direct field write.
Mutating Through a Pointer
A pointer does not bypass immutability. Writing through *T still requires the pointed-to value to be mutable, so you can only take a writable pointer to a var struct:
var p = Point { x: 0.0, y: 0.0 };
let ptr = &p;
ptr.x = 5.0; // OK — p is var
let q = Point { x: 0.0, y: 0.0 };
let qp = &q;
qp.x = 5.0; // error: q is immutableThis is also why an instance method that mutates self can only be called on a var receiver — see Methods.
Other Composite Types
The same deep rule covers the other value types: a tuple or a fixed-size array (T[N]) is mutable only when bound with var.
A dynamic slice (T[]) is the exception, because it is a view rather than a value: a let slice fixes the header (its data pointer and length) while the elements it refers to may still be written through it. Bind the slice with let to keep it pointing at the same region; the mutability of the elements depends on the storage they live in.
See Also
- Immutable Variables (
let) — the default binding - Mutable Variables (
var) — enabling field changes - Structures — value semantics and field access
- Pointers to Fields and Members — writing through a pointer