2.5 Data Types and Type Annotations

Rust requires every variable to have a definite type, either inferred by the compiler or explicitly specified. Once a variable is assigned a type, it cannot change throughout its lifetime. This ensures type safety while preventing unintended type mismatches.

2.5.1 Basic Data Types

  • Integers: i8, i16, i32, i64, i128, isize (signed) and u8, u16, u32, u64, u128, usize (unsigned)
  • Floating-Point: f32, f64
  • Boolean: bool
  • Character: char (4 bytes, supporting Unicode scalar values)

Integer and floating-point data types include their bit width in the type name (for example, u8 is an 8-bit unsigned integer).
usize and isize scale with the target platform’s pointer size (similar to size_t or ptrdiff_t in C/C++). Rust’s char represents a Unicode scalar value, unlike C’s single-byte char.

2.5.2 Type Inference

Rust can infer types based on usage:

fn main() {
    let x = 42;   // i32 inferred
    let y = 3.14; // f64 inferred
    println!("x = {}, y = {}", x, y);
}

2.5.3 Explicit Type Annotation

When inference is unclear, or you need a different default, specify the type:

fn main() {
    let x: u8 = 255;
    println!("x = {}", x);
}

2.5.4 Comparison with C

In C, int x = 42; typically yields a 32-bit integer, though the size can vary by platform. C99 introduced stdint.h for fixed-width types (for example, int32_t), similar to Rust’s explicit-width types.