[Rust Series 3] Variables, Immutability, and Basic Data Types

한국어 버전

Once your environment is ready, you need a firm grip on variables and data types before writing real code. Rust treats every variable as immutable unless you use mut. Session 3 builds intuition for immutability and walks through scalar types plus composite types such as tuples and arrays.

New terms in this post

  1. Immutability: The default Rust behavior where variables cannot change after creation unless you explicitly make them mutable.
  2. Scalar type: A type that represents a single value at a time (i32, f64, bool, char, and so on).
  3. Tuple: A fixed-length collection that groups values in order, even if their types differ.
  4. Array: A fixed-length collection that stores values of the same type; the length is part of the type.

Core ideas

  • Variables declared with let are immutable by default; use let mut when you actually need to change them.
  • Shadowing with let creates a brand-new variable rather than modifying the old one.
  • Rust infers types, but you can annotate with : Type when clarity matters.
  • Scalar types center on integers (i32, u64), floats (f32, f64), booleans (bool), and characters (char).
  • Tuples group multiple values in order; use dot indexing or pattern destructuring.
  • Arrays store values of the same type with a fixed length, preparing you for slices later (Session 7).

Code along

1. let and mut

fn main() {
    let language = "Rust"; // immutable
    let mut version = 1;    // mutable

    println!("{} v{}", language, version);
    version += 1;
    println!("Next version: v{}", version);
}

language will trigger a compile error if you try to change it, while version can increase because it uses mut.

2. Explicit scalar types

fn main() {
    let signed: i32 = -42;
    let unsigned: u64 = 2026;
    let pi: f64 = 3.14159;
    let ready: bool = true;
    let grade: char = 'A';

    println!("signed = {signed}, unsigned = {unsigned}");
    println!("pi = {pi}, ready = {ready}, grade = {grade}");
}

Literals can carry suffixes (42u8, 1.0f32). Rust defaults to i32 for integers and f64 for floats.

3. Shadowing

fn main() {
    let steps = 5;
    let steps = steps + 1;

    println!("steps = {steps}");
}

The second let steps introduces a new variable that happens to reuse the name. Shadowing is different from mut: shadowing redeclares, while mut modifies the original binding.

4. Tuples

fn main() {
    let user: (&str, u32, bool) = ("Jisoo", 3, true);

    println!("Name: {}", user.0);
    println!("Level: {}", user.1);
    println!("Active: {}", user.2);

    let (name, level, active) = user; // destructuring
    println!("{name} / {level} / {active}");
}

Tuples stay fixed in length and allow mixed types. Get comfortable with dot indexing first, then treat destructuring as an optional convenience.

5. Arrays

fn main() {
    let scores = [95, 88, 76, 100];
    let zeros = [0; 5]; // length 5, every element is 0

    println!("First score: {}", scores[0]);
    println!("Array length: {}", scores.len());

    for score in scores {
        println!("Score: {score}");
    }
}

Array length is part of its type, so [u8; 3] and [u8; 4] are different types.

Quick summary:

  • Tuple: Can mix types, length is fixed.
  • Array: Same type only, length is fixed.
  • Both: Compile-time length.

Why it matters

  • Immutability reduces bugs from unexpected changes and forces you to mark mutable state intentionally.
  • Type clarity helps you read compiler errors and track variable lifetimes when you start learning ownership and borrowing.
  • Understanding tuples and arrays makes it easier to connect future topics like structs, slices, and iterators.

Practice

  1. Run cargo new data-playground --bin, try reassigning an immutable variable in main.rs, and capture the compiler message.
  2. Write a loop that finds the maximum value in an integer array and experiment with summing values with and without mut.
  3. Create a small function that returns a tuple such as (sum, average) and destructure the result.
  4. Explain why let shadowed = 5; let shadowed = shadowed + 1; declares a new variable instead of mutating the old one.

Wrap-up

Immutability, scalar types, tuples, and arrays set your baseline for Rust's syntax. With this intuition you can track scope and state when functions and control flow appear. Session 4 moves on to defining functions with fn plus steering execution with if and loops.

💬 댓글

이 글에 대한 의견을 남겨주세요