DEV Community

Cover image for [Rust Guide] 3.1. Variables and Mutability
SomeB1oody
SomeB1oody

Posted on

[Rust Guide] 3.1. Variables and Mutability

3.1.0. Before the Main Content

Welcome to Chapter 3 of Rust self-study. There are 6 sections in total:

  • 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 small game in Chapter 2 (beginners who havenโ€™t read it are strongly recommended to do so), you should already have learned the basic Rust syntax. In Chapter 3, we will go one level deeper and understand general programming concepts in Rust.

If you like it, please like, bookmark, and follow

3.1.1. Declaring Mutable/Immutable Variables

  • Variables are declared using the let keyword

  • By default, variables are immutable. The following is an incorrect example, with the error shown in the comment:

fn main(){
    let machine = 6657;
    machine = 0721; // Error: cannot assign twice to immutable variable
    println!("machine is {}", machine);
}
Enter fullscreen mode Exit fullscreen mode
  • Add mut after let to declare a mutable variable. The following is a correct example:
fn main(){
    let mut machine = 6657;
    machine = 721;
    println!("machine is {}", machine);// Output: machine is 721
}
Enter fullscreen mode Exit fullscreen mode

3.1.2 Variables and Constants

Many people who start learning Rust cannot clearly distinguish between immutable variables and constants (constant). Although constants are also immutable once assigned, they differ significantly from immutable variables:

  • Constants cannot use mut; once declared, they are immutable.
  • Constants must be declared using const, and their type must be explicitly specified; immutable variables do not require explicit type annotation.
  • Constants can be declared in any scope, including the global scope.
  • Constants can only be bound to constant expressions and cannot be bound to the result of a function call or values that can only be computed at runtime.
  • During program execution, constants are always valid within their declared scope.
  • Naming convention: constants in Rust use all uppercase letters, with underscores separating words, e.g., MAX_POINTS.

Example of 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  
}
Enter fullscreen mode Exit fullscreen mode

Here, i32 and u32 are types. Rust allows underscores to improve readability. In this example, 6_657 can also be written as 6657. This constant can be declared globally, inside main, or in other scopes.

3.1.3 Shadowing

As briefly mentioned in the previous game example, Rust allows using a new variable with the same name to hide the previous one. This is called shadowing (when a variable, function, or type name is redefined in the current scope, it hides the one with the same name from an outer scope). Each time shadowing occurs, the old value and type are replaced.

Example:

fn main(){
let a = 1;
println!("{}",a);
let a = "one";
println!("{}",a);
}
Enter fullscreen mode Exit fullscreen mode

This does not produce an error, and the output is:

1
one
Enter fullscreen mode Exit fullscreen mode

When the program executes line 2, a is 1. At line 4, a is reused, so the old value is discarded and replaced with "one".

Important differences between shadowing and mutability:

  • In shadowing, the new variable declared with let is still immutable
  • In shadowing, the type of the new variable can be different from the previous one
fn main(){
    let machine = "wjq";
    let machine = 6657;
    println!("{}",machine);
}
Enter fullscreen mode Exit fullscreen mode

This works because of shadowing.

fn main(){  
    let mut machine = "wjq";  
    machine = 6657;  
    println!("{}",machine);// Error: expected `&str`, found integer
}
Enter fullscreen mode Exit fullscreen mode

This fails because Rust is strongly typed, and the variable type is fixed at first declaration.

Top comments (0)