Rust Data Types

Rust is statically typed, and its scalar and compound types -- integers, floats, booleans, characters, and tuples -- form the vocabulary for everything else you'll write.

Scalar Types at a Glance

A scalar type represents a single value. Rust has four of them: integers, floating-point numbers, booleans, and characters. Every other type in the language -- strings, structs, enums, collections -- is built out of these plus compound types like tuples and arrays.

Integer Types

Integers come in signed (`i`) and unsigned (`u`) flavors, each available at several bit widths. `i32` is the default Rust reaches for when it can't infer anything more specific, and it's fast on essentially every modern CPU.

  • `i8`, `i16`, `i32`, `i64`, `i128` -- signed integers, from 8 to 128 bits
  • `u8`, `u16`, `u32`, `u64`, `u128` -- unsigned integers, always non-negative
  • `isize` / `usize` -- sized to match the pointer width of the target machine, used for indexing collections

Working with Integers

fn main() {
    let age: u8 = 30;
    let population: i64 = 8_000_000_000;
    let byte_max = u8::MAX;

    println!("Age: {}, world population: {}, u8 max: {}", age, population, byte_max);
}

Floating-Point Types

Rust has two floating-point types, `f32` and `f64`, both following the IEEE-754 standard. `f64` is the default because on modern hardware it's roughly as fast as `f32` while offering far more precision.

Floating-Point Arithmetic

fn main() {
    let price: f64 = 19.99;
    let quantity = 3;
    let total = price * quantity as f64;

    println!("Total: {:.2}", total);
}

Booleans, Characters, and Tuples

`bool` holds either `true` or `false` and takes up a single byte. `char` represents a single Unicode scalar value -- four bytes wide, so it can hold far more than plain ASCII, including accented letters, CJK characters, and emoji. Tuples group values of different types together into one compound value, accessed by position with `.0`, `.1`, and so on.

Bool, Char, and Tuple Basics

fn main() {
    let is_active: bool = true;
    let grade: char = 'A';
    let point: (f64, f64, &str) = (3.5, -1.2, "origin offset");

    println!("Active: {}, grade: {}, coordinates: ({}, {}) -- {}", is_active, grade, point.0, point.1, point.2);
}
TypeSizeExample
i324 bytes-273
u81 byte255
f648 bytes3.14159
bool1 bytetrue
char4 bytes'R'
Note: Numeric literals can carry their type as a suffix, like `4u8` or `2.5f32`, which is handy when inference alone can't tell which type you meant.
Note: Integer overflow panics in debug builds but silently wraps around in release builds. Never rely on that wrapping behavior -- use methods like `checked_add` or `wrapping_add` if you need to handle overflow explicitly.

Exercise: Rust Data Types

Does Rust perform implicit conversion between an i32 and an f64?