Skip to main content
Brave Programmer Logo

BraveProgrammer

BraveProgrammer

HomeProjectsBlogsCoursesLessonsAbout

Site footer

BraveProgrammer

Free coding courses, practical tutorials, and real projects from BraveProgrammer. Learn web development with React, Next.js, and TypeScript.

Navigation

  • Home
  • Projects
  • Blogs
  • Courses

Resources

  • About
  • Lessons

© 2026 BraveProgrammer. All rights reserved.

  1. Courses
  2. /
  3. Rust Fundamentals

Lesson 5 of 50 · rust

Variables and Mutability

Duration: 12 minutes

Variables and Mutability\n\nOne of Rust's core principles is immutability by default. This prevents entire categories of bugs and encourages careful thinking about what data your program modifies.\n\n## Immutable Variables\n\nAll variables are immutable by default:\n\nrust\nfn main() {\n let x = 5;\n println!(\"x = {}\", x); // prints 5\n // x = 6; // ERROR!\n}\n\n\nTrying to modify an immutable variable produces a compiler error. This is a feature, not a limitation—the compiler prevents accidental mutations.\n\n## Mutable Variables\n\nExplicitly mark variables as mutable with mut:\n\nrust\nfn main() {\n let mut x = 5;\n println!(\"x = {}\", x); // prints 5\n x = 6;\n println!(\"x = {}\", x); // prints 6\n}\n\n\nThe mut keyword signals intent: "This variable will change." This self-documents code.\n\n## Why Immutability by Default?\n\n### Safety\nImmutable variables can't change unexpectedly.\n\n### Concurrency\nImmutable data is thread-safe. Multiple threads safely read immutable values without synchronization.\n\n### Reasoning About Code\nImmediate clarity about whether a value can change.\n\n## Variable Shadowing\n\nDeclare a new variable with the same name, creating a new binding:\n\nrust\nfn main() {\n let x = 5;\n let x = x + 1; // Shadow: new binding\n let x = x * 2; // Another shadow\n println!(\"x = {}\", x); // prints 12\n}\n\n\nShadowing differs from mutability:\n- Shadowing: Creates new variable (possibly different type)\n- Mutability: Changes value of same variable\n\nUse shadowing for transformations:\n\nrust\nfn main() {\n let input = \" 42 \";\n let input = input.trim(); // Shadow: trimmed string\n let input: i32 = input.parse().unwrap(); // Shadow: parse to number\n println!(\"Number: {}\", input + 10); // 52\n}\n\n\n## Constants vs Immutable Variables\n\nrust\nconst MAX_POINTS: u32 = 100_000; // Constant\nlet fixed_value = 42; // Immutable variable\n\n\n| Aspect | const | let |\n|--------|---------|-------|\n| Evaluated | Compile time | Runtime |\n| Type | Required | Inferred |\n| Scope | Global | Block |\n\nUse constants for compile-time known values.\n\n## Type Annotations\n\nExplicitly specify types, though Rust usually infers them:\n\nrust\nlet x = 5; // Inferred as i32\nlet x: i32 = 5; // Explicit\nlet mut y: f64 = 3.14; // Explicit on mutable\n\n\n## Practical Example\n\nrust\nfn main() {\n let username = \"alice\"; // Immutable\n println!(\"User: {}\", username);\n \n let mut score = 0; // Mutable for game tracking\n score += 10;\n score += 5;\n println!(\"Score: {}\", score);\n \n const WINNING_SCORE: i32 = 100;\n if score >= WINNING_SCORE {\n println!(\"Victory!\");\n }\n}\n\n\n## Best Practices\n\n1. Start immutable: Add mut only when necessary\n2. Shadow for transformations: When data changes type or meaning\n3. Constants for config: Fixed values used throughout code\n4. Clear intent: mut shows your intentions to other developers

Previous: Understanding Cargo ProjectsNext: Basic Data Types