Start learning free

LESSON 4 OF 414 · WELCOME TO RUST

Variables in Rust: let, Types and Initialization

Lesson Read the full explanation

In computer science, data is anything that is meaningful to the computer. Rust provides a large number of data types, the most frequently used being:

  • i32 - represents integer numbers like 3 and -12
  • f64 - represents floating point numbers like 3.14
  • char - represents a single character like 'a', 'Z' or '?'
  • &str - represents a sequence of characters like "John Doe"
  • bool - represents one of two values: true or false

For example, computers distinguish between numbers, such as the number 12, and strings, such as "12", "dog", or "123 cats", which are collections of characters. Computers can perform mathematical operations on a number, but not on a string.

Variables are containers for storing values. A piece of information / data lives in memory and we use a variable to store and descriptively label that data.


Variable declaration:

To create / declare a variable, we use let followed by the variable's name, then a colon and the variable's data type, like so:

let name: &str;

creates a string variable named name.


Variable initialization:

We can initialize a variable to an initial value in the same line as it is created using the assignment operator (=). This code:

let name = "AlgoCademy";

creates a new string variable named name and assigns it an initial value of "AlgoCademy".

When executing this code, Rust will allocate some memory, then it will store the string "AlgoCademy" in that memory and finally will attach this name label to that memory location.

You can think of this memory location as a box. In that box, we put string "AlgoCademy". Then, we put the label name on this box.


Accessing values in variables:

Now we can use this label anywhere in our program to access the value in that box. We can print it for example:

// We create and initialize two variables:
let name = "AlgoCademy";
let age = 10;

// We access the variables:
println!("{}", name);
println!("{}", age);

The output of this code is:

AlgoCademy
10

Important notice:

We almost never want to create a variable without initializing it! It's a bad coding practice and can create a lot of problems.


Immutability by default:

In Rust, let x = 5 is immutable — trying to reassign it is a compile error. Add mut to allow changes, or 'shadow' the name with a new let.

let x = 5;
x = 6;          // error[E0384]: cannot assign twice to immutable variable `x`

let mut y = 5;
y = 6;          // OK — y is mutable

let x = x + 1;  // OK — shadowing creates a fresh x

Assignment
Follow the Coding Tutorial and let's create some variables!


Hint
Look at the examples above if you get stuck.


STEP 1 OF 2
    Ctrl + Enter to check

    RUST · WELCOME TO RUST

    Variables in Rust, explained

    Data and data types

    Everything a program works with is data: numbers, text, true/false answers. Rust sorts data into types, and the most common ones to start with are:

    TypeHoldsExamples
    i32integer numbers3, -12
    f64floating-point numbers3.14
    chara single character'a', 'Z', '?'
    &strtext (a string slice)"John Doe"
    booltrue or falsetrue, false

    The type matters because it decides what you can do. You can do arithmetic on the number 12, but not on the text "12", which is two characters. Adding them together is a compile error: 12 + "12" reports that you cannot add &str to an integer.

    What a variable is

    A variable is a name attached to a value that the program keeps in memory. You can picture a box with a label: the value is in the box, and the variable name is the label. Anywhere you write the name, you get the value.

    Creating a variable with let

    In Rust a variable is introduced with the keyword let. The type can be written after a colon:

    let name: &str;
    

    This declares a variable named name of type &str without giving it a value yet. Rust will not let you read it until a value has been assigned. The following program does not compile:

    let x: i32;
    println!("{}", x);
    

    The error says that x is "used here but it isn't initialized". For this reason, declaring a variable and giving it a value in the same statement is the normal way to write it.

    Initializing a variable

    The assignment operator = stores a value in the variable as it is created:

    let name = "AlgoCademy";
    let age = 10;
    

    Here the types are not written. Rust works them out from the values: "AlgoCademy" is a &str, and an integer literal such as 10 becomes an i32 unless something else asks for a different integer type. This is called type inference. You can still write the type when you want to be explicit, as in let age: i32 = 10;. Both forms do the same thing.

    Using a variable

    Once a variable exists, you use its name to get the value, for example to print it:

    let name = "AlgoCademy";
    let age = 10;
    println!("{}", name);
    println!("{}", age);
    
    AlgoCademy
    10
    

    A variable can also appear in a calculation: after let age = 10;, the expression age + 1 gives 11.

    Variables are immutable by default

    This is the biggest difference between Rust and many other languages. A variable created with plain let cannot be changed after it is given its value:

    let age = 10;
    age = 11;
    

    The compiler rejects this with "cannot assign twice to immutable variable age" and suggests the fix. To allow changes, add the keyword mut:

    let mut score = 10;
    score += 5;
    println!("{}", score);
    
    15
    

    Even a mutable variable keeps its type. After let mut score = 10;, the line score = "ten"; is a compile error, because a text value doesn't fit in an integer variable. Prefer plain let and add mut only when the value really has to change.

    Shadowing

    You can also reuse a name by writing let again. The new variable shadows the old one:

    let x = 5;
    let x = x + 1;
    println!("{}", x);
    
    6
    

    This creates a new variable that happens to have the same name. It is different from mut, since a shadowing let may even change the type.

    Naming and common mistakes

    • Variable names use snake_case: lowercase words joined by underscores, such as first_name. The compiler warns about other styles.
    • Strings go in double quotes and numbers don't. let age: i32 = "31"; fails with "expected i32, found &str".
    • Leaving out the ; after a let statement is a syntax error.
    • A declared variable that is never used triggers a warning ("unused variable"). It is only a warning, and the program still runs.
    • A variable that is declared without a value can't be read until it is assigned.

    The lesson's exercise

    The exercise has two parts:

    1. Create a variable named name, annotate its type as &str, and initialize it with "Michael". A string literal is a &str, so the types agree.
    2. On the next line, create a variable named age, annotate its type as i32, and initialize it with the number 31. The number goes without quotes.
    let name: &str = "Michael";
    let age: i32 = 31;
    

    Neither variable needs mut, since neither is changed afterwards.

    Key takeaways

    • A variable is a name for a value, created with let.
    • Types such as i32, f64, char, &str and bool describe what a value is. Rust can infer them, or you can write them after a colon.
    • Variables are immutable unless declared with let mut.
    • Always give a variable its value when you create it.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free