Skip to content

Rust Data Types

Every value in Rust has a type — a label that tells the compiler what kind of data it is (a whole number, a decimal, text, true/false, and so on). Knowing the type lets Rust check your code for mistakes before it runs.

As you saw with variables, Rust can usually infer the type for you. But it helps to know the main types by name, because you’ll see them in error messages and function signatures.

Integers are numbers without a decimal point, like 42 or -7. Rust has several integer types that differ by size and whether they allow negative numbers:

Type Signed? Typical use
i32 Yes (can be negative) The default — use this unless you have a reason not to
u32 No (0 and up) Counts, sizes, things that can’t be negative
i64 / u64 Yes / No Very large numbers
usize No Indexing into collections
fn main() {
let temperature = -5; // i32 by default
let count: u32 = 100; // explicitly unsigned
println!("{temperature} degrees, count is {count}");
}
▶ Try it Yourself

For numbers with a decimal point, use floating-point types. There are two: f64 (the default, double precision) and f32.

fn main() {
let pi = 3.14159; // f64 by default
let price: f32 = 9.99;
println!("Pi is {pi}, price is {price}");
}

Stick with f64 unless you specifically need the smaller f32 — it’s more precise and just as fast on modern hardware.

A boolean (bool) is the simplest type: it’s either true or false. You’ll use these constantly in if statements and conditions.

fn main() {
let is_logged_in = true;
let has_permission: bool = false;
println!("logged in: {is_logged_in}, permission: {has_permission}");
}
▶ Try it Yourself

A char holds a single character, written with single quotes ' '. A Rust char can be any single Unicode scalar value — which covers most emoji, though a few complex ones (like flags or emoji built from multiple joined characters) don’t fit in just one.

fn main() {
let letter = 'R';
let symbol = '$';
let crab = '🦀';
println!("{letter} {symbol} {crab}");
}

Text in Rust is written with double quotes. There are two string types you’ll meet:

  • &str — a string slice, usually text you write directly in your code (a “string literal”).
  • String — a growable, owned piece of text you can change and build up.
fn main() {
let greeting = "Hello"; // &str
let mut name = String::from("Ferris"); // String
name.push_str(" the crab"); // Strings can grow
println!("{greeting}, {name}!");
}
▶ Try it Yourself

Don’t worry about the difference between &str and String yet — it connects to ownership, which you’ll learn soon. For now: use "..." for text and reach for String when you need to build or modify it.

Most of the time Rust infers the type. But sometimes it needs a hint — for example, when parsing text into a number. You add a type with a colon:

let x: i32 = 42;
let y: f64 = 3.5;
let active: bool = true;
Type What it holds Example
i32 Whole number (default) let n = 42;
u32 Non-negative whole number let n: u32 = 42;
f64 Decimal number (default) let pi = 3.14;
bool true or false let ok = true;
char One character let c = 'A';
&str Text literal let s = "hi";
String Growable text let s = String::from("hi");
  • Every value has a type; Rust usually infers it.
  • Whole numbers → i32 (default). Decimals → f64 (default).
  • bool is true/false; char is a single character in single quotes.
  • Text is written in double quotes: &str for literals, String for growable text.

Quick check

1. What is the default integer type in Rust if you don't specify one?

2. How does Rust distinguish a char literal from a string literal?

3. Which type is a growable, owned piece of text you can modify?

4. What is the default floating-point type in Rust?

5. Which type would `let greeting = "Hello";` infer to?

Score: 0 / 5