Module lessons (1/2)
Variables and Mutability
In Rust, variable and memory management is guided by two fundamental principles: safety and control. For this reason, unlike many other programming languages, variables in Rust are immutable by default.
This means that once a value is assigned to a variable, it cannot be changed. If you attempt to modify it, the compiler will raise an error.
Immutable Variables and the mut Keyword
To declare a variable, we use the let keyword:
let x = 5; // Immutable by default
// x = 6; // ERROR! The compiler will refuse to build this code.
If you need to modify the value of a variable, you must explicitly make it mutable by using the mut keyword right after let:
let mut y = 10; // Mutable
println!("Il valore di y e: {}", y);
y = 15; // Valid!
println!("Il valore modificato di y e: {}", y);
Using the mut prefix clearly communicates to the compiler and to anyone reading the code that the value will change during execution.
Shadowing
Rust also allows the concept of shadowing, which is the re-declaration of a variable with the same name using the let keyword again. The new variable "shadows" (or covers) the previous one:
let x = 5;
let x = x + 1; // Shadowing: x is now 6
let x = x * 2; // Shadowing: x is now 12
Unlike mut, shadowing allows you to:
- Change the data type of a variable while keeping the same name.
- Maintain the immutability of the variable after the transformations.
let spaces = " "; // Type: &str (string)
let spaces = spaces.len(); // Type: usize (number)
Usefulness of Shadowing and Scopes
Shadowing is not limited to the same block; it can be used within nested blocks ({}) to temporarily override a value. When the inner block ends, the original variable becomes visible again:
let x = 5;
{
let x = x * 2; // Shadowing valid only inside the block
println!("Value in the inner block: {}", x); // Prints 10
}
println!("Value in the outer block: {}", x); // Prints 5
This mechanism is extremely safe and efficient because it occurs entirely at compile-time, ensuring type safety without any runtime performance overhead.
Try it yourself
Declare a mutable variable named x with an initial value of 5. Next, add 10 to x and print it to the screen using the println! macro.
Show hint
Declare the variable with `let mut x = 5;`, then increment it with `x += 10;` (or `x = x + 10;`) and finally print it with `println!('{}', x);`.
Solution available after 3 attempts
Declare an immutable variable y with a value of 10. Shadow y by declaring it again with let to multiply its previous value by 2, and finally print it using println!.
Show hint
Use `let y = 10;`, then shadow it by declaring it again with `let y = y * 2;` and finally use `println!` to display it.
Solution available after 3 attempts
Declare an immutable variable named input containing the string value "42". Shadow input by declaring it as an integer of type i32, converting the original value via input.parse::<i32>().unwrap(). Finally, print it using the println! macro.
Show hint
Declare `let input = "42";`, then shadow it with `let input: i32 = input.parse().unwrap();` and print it using `println!("{}", input);`.
Solution available after 3 attempts