3.1.0. Before We Begin
Welcome to Chapter 3 of this Rust self-study series. It has 6 sections:
- Variables and Mutability (this article)
- Data Types: Scalar Types
- Data Types: Compound Types
- Functions and Comments
- Control Flow:
if else - Control Flow: Loops
Through the guessing game in Chapter 2 (beginners who have not read it are strongly encouraged to take a look), you should now have learned the basic Rust syntax. In Chapter 3, we will go one level deeper and learn the general programming concepts in Rust.
If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.
3.1.1. Declaring Mutable and Immutable Variables
Use the
letkeyword to declare a variable.By default, variables are immutable. Here is an incorrect example; the error is shown in the comment:
fn main(){
let machine = 6657;
machine = 0721; // Error: cannot assign twice to immutable variable
println!("machine is {}", machine);
}
- You must add
mutafterletto declare a mutable variable. Here is a successful example; the output is shown in the comment:
fn main(){
let mut machine = 6657;
machine = 721;
println!("machine is {}", machine); // Output: machine is 721
}
3.1.2. Variables and Constants
Many people who are just starting to learn Rust get confused about the difference between immutable variables and constants.
Constants are immutable after they are bound to a value, but they differ from immutable variables in several important ways:
- Constants cannot use
mut; once declared, they are immutable. - Constants must be declared with the
constkeyword, and their type must be explicitly annotated; immutable variables do not have to be. - Constants can be declared in any scope, including the global scope.
- Constants can only be bound to constant expressions; they cannot be bound to the result of a function call or to values that can only be computed at runtime.
- During program execution, a constant remains valid for the entire scope in which it is declared.
- Naming convention: Rust constants use all-uppercase letters, with underscores between words, for example:
MAX_POINTS.
Here is an example of a constant declaration:
const WJQ: i32 = 66570721;
fn main(){
const WJQ_MACHINE: u32 = 6_657;
let mut machine = 6657;
machine = 721;
println!("machine is {}", machine); // Output: machine is 721
println!("WJQ is {}", WJQ); // Output: WJQ is 66570721
println!("WJQ_MACHINE is {}", WJQ_MACHINE); // Output: WJQ_MACHINE is 6657
}
i32 and u32 are the types. Rust allows underscores to improve readability. In this example, 6_657 could also be written as 6657.
This constant can be declared globally, inside main, or in any other scope.
3.1.3. Shadowing
In the guessing game from earlier, we already briefly mentioned that Rust allows a new variable with the same name to shadow the original one. This is called shadowing (when a name is redefined in the current scope, it hides a variable, function, or type with the same name from an outer scope). Each time a name is shadowed, the original variable's value and type are replaced by the new variable. This lets you reuse the same variable name without declaring a brand-new one.
Here is an example:
fn main(){
let a = 1;
println!("{}", a);
let a = "one";
println!("{}", a);
}
This program does not error, and it prints:
1
one
When the program reaches the second line, a is bound to 1, so it prints 1. On the fourth line, the program notices that a is being reused, so it discards the original value 1 and binds a to "one", which is why the next line prints one. This is shadowing.
Note that shadowing and making a variable mutable are different:
- In shadowing, the new variable declared with
letis still immutable. - In shadowing, the type of the newly declared variable with the same name can be different from the previous one.
fn main(){
let machine = "wjq";
let machine = 6657;
println!("{}", machine);
}
The program above uses shadowing and will not error. The second let machine = 6657; declares a brand-new variable, which has nothing to do with the previous machine.
fn main(){
let mut machine = "wjq";
machine = 6657;
println!("{}", machine); // Error: expected `&str`, found integer
}
The program above uses a mutable variable. Rust is a strongly typed language, and a variable's type is determined when it is first declared. The assignment machine = 6657 tries to assign an integer to a string-typed variable, so the types do not match and the compiler reports an error: expected &str, found integer.
Top comments (0)