In Rust, data structures are immutable by default. This means that any variable or reference declared without the mut keyword cannot be changed after initialization.
let mut value = 10; // mutable variable value += 5; let value2 = 10; // immutable variable // value2 += 5; // compilation error: cannot assign twice to immutable variable
The same logic applies to struct fields:
struct Point { x: i32, y: i32 } let mut pt = Point { x: 1, y: 2 }; pt.x = 5; // OK, since pt is declared as mut
However, mutability only affects the "top level" of the variable: if a structure is stored behind an immutable reference, its data cannot be changed even if declared as mut within the structure.
Another way to bypass limitations is to use special types like RefCell<T> or atomic containers. This allows changing data inside seemingly immutable containers through "interior mutability", for example:
use std::cell::RefCell; struct Counter { count: RefCell<i32>, } let counter = Counter { count: RefCell::new(0) }; *counter.count.borrow_mut() += 1; // safe, despite the absence of mut
Question: Can you change the value of a struct field if the variable itself is not declared as mut, but the field is explicitly declared as mut in the struct?
Typical incorrect answer: Yes, if the field is declared as mut, it can be changed.
Correct answer: The mut keyword cannot be used when declaring a struct field. Mutability only refers to the variable itself or the obtained reference. To modify a struct field, you must either declare the variable as mut or use types of "interior mutability" (for example, RefCell).
Example:
struct Foo { val: i32 } // field declared without mut let mut foo = Foo { val: 1 }; foo.val = 2; // OK let foo2 = Foo { val: 3 }; foo2.val = 4; // error! variable is not mutable
Story
In a large project, one of the developers tried to change a struct field, thinking that declaring the field with mut ("struct S { mut x: i32 }") would provide the needed mutability. This could not compile, and the refactoring process dragged on for several hours until it was explained to him that mutability is a feature of the variable's ownership, not the structure.
Story
In a multithreading-related project, all logic for controlling data access was held in a global static structure. Not knowing about the possibilities of "interior mutability" via
RefCell, the team wrote overly complex locking and racing mechanisms instead of a simple solution usingArc<Mutex<T>>orRwLock<T>.
Story
A developer forgot to declare a function argument as mut in the signature, and the function could not modify the passed structure, which caused a bug to manifest only in production (data was not updated after the function call). Knowing that by default passing goes by immutable reference would have allowed him to avoid the absence of an error at early stages.