Variables and Data Types
TL;DR: Rust variables are immutable by default — use
mutto allow reassignment. Rust is statically typed but infers types automatically. Scalar types include integers (i32,u64), floats (f64), booleans, and characters. All type conversions must be explicit; Rust never coerces types silently. Estimated: 20 minutes.
In this lesson, we'll explore how Rust handles variables and its basic data types. You'll learn about variable declaration, mutability, and the most common data types you'll use in your Rust programs.
Variables and Mutability
In Rust, variables are immutable by default - a key feature that promotes safer code:
fn main() {
let x = 5; // Immutable by default
println!("The value of x is: {}", x);
// This would cause a compile error:
// x = 6; // Cannot assign twice to immutable variable
// To make a variable mutable, use 'mut':
let mut y = 5;
println!("The value of y is: {}", y);
y = 6; // This works!
println!("The value of y is now: {}", y);
}
Basic Data Types
Rust is a statically typed language, which means it must know the types of all variables at compile time. The compiler can usually infer the type based on how we use the variable.
Scalar Types
Integers
fn main() {
let a: i32 = 42; // 32-bit signed integer
let b: u32 = 42; // 32-bit unsigned integer
let c = 42_i64; // 64-bit signed integer
let d = 42_u64; // 64-bit unsigned integer
println!("Different integer types: {}, {}, {}, {}", a, b, c, d);
}
Floating-Point Numbers
fn main() {
let x = 2.0; // f64 (default)
let y: f32 = 3.0; // f32
println!("Floating point numbers: {}, {}", x, y);
}
Boolean
fn main() {
let t = true;
let f: bool = false;
println!("Boolean values: {}, {}", t, f);
}
Character
fn main() {
let c = 'z';
let z: char = 'ℤ';
let heart_eyed_cat = '😻';
println!("Characters: {}, {}, {}", c, z, heart_eyed_cat);
}
Type Conversion
Rust requires explicit type conversion in most cases:
fn main() {
let x = 42_i32;
// Convert i32 to f64
let y = x as f64;
// String to number conversion
let str_num = "42";
let parsed_num = str_num.parse::<i32>().unwrap();
println!("Original: {}", x);
println!("Converted to float: {}", y);
println!("Parsed from string: {}", parsed_num);
// Try changing these values and conversions!
}
Practice Exercises
Try these exercises in the playground above:
- Create variables of different numeric types and perform some basic arithmetic
- Try converting between different numeric types using the
askeyword - Create a string from a number using the
to_string()method - Parse a string containing a floating-point number into an
f64
Remember: Rust's type system is one of its strongest features, helping catch potential errors at compile time rather than runtime! Once you're comfortable with types, the next big concept is ownership — Rust's most distinctive feature.
Key Takeaways
- Variables in Rust are immutable by default — use
mutwhen you need to change a value - Rust is statically typed: the compiler must know every variable's type at compile time
- Scalar types include integers (
i32,u64), floats (f64), booleans, and characters - Type conversion requires explicit casting with
as— Rust never converts types implicitly - Use
.parse::<T>()to convert strings to numbers, handling potential errors with.unwrap()or?
Next Steps
You now know how Rust stores and represents data — from integers and floats to booleans, characters, and type conversions. But data alone isn't enough; you need to make decisions and repeat actions based on that data. In the next lesson, we'll cover control flow — if expressions, loop/while/for loops, and an early look at match. You'll see how Rust's control flow constructs are expressions that return values, which leads to more concise and idiomatic code.
Next lesson
Control Flow
Master Rust control flow with if expressions, loops, and the match statement for conditional logic and pattern matching
25 min