R2: Mutability and Shadowing Flashcards
Rust encourages you to favor immutability
By default, variables are immutable
``` rust
fn main() {
let x = 5;
println!(“The value of x is: {x}”);
x = 6;
println!(“The value of x is: {x}”);
}
~~~
``` console
error[E0384]: cannot assign twice to immutable variable x
~~~
But mutability can be very useful
Adding mut
.
Example:
``` rust
fn main() {
let mut x = 5;
println!(“The value of x is: {x}”);
x = 6;
println!(“The value of x is: {x}”);
}
~~~
```console
The value of x is: 5
The value of x is: 6
~~~
Constants VS Variables
- you aren’t allowed to use mut with constants
- you declare constants using the const keyword instead of the let keyword
- the type of the value of a constants must be annotated
- Constants can be declared in any scope, including the global scope, which makes them useful for values that many parts of code need to know about.
- The last difference is that constants may be set only to a constant expression, not the result of a value that could only be computed at runtime.
Example:
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
Constants scope
Constants are valid for the entire time a program runs, within the scope in which they were declared.
Constants are valid for the entire time a program runs, within the scope in which they were declared. This property makes constants useful for values in your application domain that multiple parts of the program might need to know about, such as the maximum number of points any player of a game is allowed to earn, or the speed of light.
Shadowing
As you saw in the guessing game tutorial in Chapter 2, you can declare a new variable with the same name as a previous variable. Rustaceans say that the first variable is shadowed by the second, which means that the second variable is what the compiler will see when you use the name of the variable. In effect, the second variable overshadows the first, taking any uses of the variable name to itself until either it itself is shadowed or the scope ends. We can shadow a variable by using the same variable’s name and repeating the use of the let keyword as follows:
Example:
```rust
fn main() {
let x = 5;
let x = x + 1; { let x = x * 2; println!("The value of x in the inner scope is: {x}"); } println!("The value of x is: {x}"); } ~~~
```console
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.31s
Running target/debug/variables
The value of x in the inner scope is: 12
The value of x is: 6
~~~
Does this code compile?
``` rust
let spaces = “ “;
let spaces = spaces.len();
~~~
Yes.
The first spaces variable is a string type and the second spaces variable is a number type. Shadowing thus spares us from having to come up with different names, such as spaces_str and spaces_num; instead, we can reuse the simpler spaces name.
Does this code compile?
``` rust
let mut spaces = “ “;
spaces = spaces.len();
~~~
No. However, if we try to use mut for this, as shown here, we’ll get a compile-time error:
~~~
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
error[E0308]: mismatched types
–> src/main.rs:3:14
|
2 | let mut spaces = “ “;
| —– expected due to this value
3 | spaces = spaces.len();
| ^^^^^^^^^^^^ expected &str
, found usize
For more information about this error, try rustc --explain E0308
.
error: could not compile variables
due to previous error
~~~
By using let, we can perform a few transformations on a value but have the variable be immutable after those transformations have been completed.