Data Types 🔢
Numbers, text, yes/no switches: every value in Rust has a type, and the compiler always knows which one. Meet the raw ingredients.
Why types matter
A type tells the computer what kind of thing a value is and how much memory it needs. Adding two numbers makes sense; adding a number to the word "banana" doesn't. Rust checks all of this before your program runs, so type mix-ups can never crash it later.
Usually you don't even write types; Rust infers them from context. But you can always be explicit with a colon:
let lucky = 7; // Rust infers: i32
let lucky: i8 = 7; // you insist: a tiny i8
Whole numbers: the integer family
Integers come in sizes (how many bits of memory) and two flavors:
i for signed (can be negative), u for unsigned (never negative).
| Type | Range | Use it for… |
|---|---|---|
i32 | ±2.1 billion | the default: almost everything |
i64 | ±9.2 quintillion | very big counts, timestamps |
u8 | 0 to 255 | bytes, color channels |
u32 | 0 to 4.3 billion | counts that can't be negative |
usize | machine-sized | indexes and lengths of collections |
let population: u32 = 8_000_000; // underscores = readable
let depth: i32 = -11_034; // negative needs a signed type
Decimal numbers: floats
let pi = 3.14159; // f64: the default, double precision
let ratio: f32 = 0.5; // f32: half the memory, less precise
let sum = 5 + 0.5; is an error:
is that integer math or decimal math? You decide, with a cast:
5 as f64 + 0.5. Explicit beats surprising.
true / false: bool
let is_hungry = true;
let has_snacks = false;
let panic_time = is_hungry && !has_snacks; // && = AND, ! = NOT, || = OR
println!("Panic? {panic_time}");
Booleans fuel every decision your program makes; they're the answer to every
comparison: 5 > 3 is true, x == y asks "equal?",
x != y asks "different?".
Single characters: char
let grade = 'A'; // single quotes for chars
let crab = '🦀'; // yes, emoji are chars; Rust speaks Unicode
let heart = '❤';
Text: &str (for now)
let greeting = "Hello, sailor!"; // double quotes for text
Text in double quotes is a string literal, type &str.
Rust actually has two string types (the other is String), and the
difference is one of the most interesting stories in the language. It needs
ownership (Lesson 6) to make sense, so we'll park it until Lesson 10.
For now, double quotes just work.
Bundles: tuples and arrays
Tuples group a few values of any mix of types, like one row on a scoreboard:
let player = ("Rusty", 42, true); // name, score, is_online
let (name, score, online) = player; // unpack all at once
println!("{name} scored {score} (online: {online})");
println!("score again: {}", player.1); // or grab by position: .0, .1, .2
Arrays hold a fixed number of values of the same type, like an egg carton:
let tides = [1.2, 0.8, 1.5, 0.9];
let first = tides[0]; // positions start at ZERO
let week = [0; 7]; // shortcut: seven zeros
println!("first tide: {first}, days: {}", week.len());
tides[99] and Rust stops the program with a clear message
instead of silently reading random memory like C would. That silent reading
(a buffer overflow) is one of the most exploited security bugs
in history. In Rust, it's simply not a thing.
Type detective
Without running it, name the type of each variable:
let a = 42;
let b = 42.0;
let c = '4';
let d = "42";
let e = 4 > 2;
Reveal answers
a: i32 (integer default) · b: f64
(float default) · c: char (single quotes) ·
d: &str (double quotes) · e: bool
(a comparison's answer is always true/false).
Trading card
Make a tuple for a creature: name (&str), power level
(i32), and legendary status (bool). Unpack it and print a
sentence like Krabby has power 9000 (legendary: true).
Reveal solution
fn main() {
let card = ("Krabby", 9000, true);
let (name, power, legendary) = card;
println!("{name} has power {power} (legendary: {legendary})");
}
Meal plan
Create an array of three meal names. Print the first and last elements,
using .len() to find the last index (careful: positions start at zero!).
Reveal solution
fn main() {
let meals = ["pancakes", "ramen", "tacos"];
println!("breakfast: {}", meals[0]);
println!("dinner: {}", meals[meals.len() - 1]);
}
Forgetting the - 1 asks for index 3 in a 3-item array (positions
0, 1, 2). Try it and read the panic message. Now you've seen Rust's bounds
checking with your own eyes.