Data Types

Scalar Data Types

Rust by example - Primitives

Rust has several categories of primitive types: integers, floating-point numbers, Booleans, unicode characters, 'Unit', and 'Never'.

Type FamilyTypesExamples
Signed Integersi8⮳, i16⮳, i32⮳, i64⮳, i128⮳, isize⮳.-8i8, -32i32.
Unsigned Integersu8⮳, u16⮳, u32⮳, u64⮳, u128⮳, usize⮳.6u8.
Floating pointf32⮳, f64⮳.0.15.
Booleanbool⮳.true, false.
Unicode Charactercharlet z: char = 'ℤ';
Unitunit⮳.The () type (aka 'void' in other languages) has exactly one value (), and is used when there is no other meaningful value that could be returned.
Nevernever⮳.! represents the type of computations which never resolve to any value at all. For example, the exit function fn exit(code: i32) -> ! exits the process without ever returning, and so returns !.

usize⮳ and isize⮳ are 32 or 64 bits, depending on the architecture of the computer.

The following illustrates the various scalar data types:

fn main() {
    // Integer types
    let a: i8 = -128; // 8-bit signed integer.
    let b: u8 = 255; // 8-bit unsigned integer.
    let c: i16 = 32767; // 16-bit signed integer.
    let d: u16 = 65535; // 16-bit unsigned integer.
    let e: i32 = 2147483647; // 32-bit signed integer (default for integers).
    let f: u32 = 4294967295; // 32-bit unsigned integer.
    let g: i64 = 9223372036854775807; // 64-bit signed integer.
    let h: u64 = 18446744073709551615; // 64-bit unsigned integer.
    let i: i128 = 170141183460469231731687303715884105727; // 128-bit signed integer.
    let j: u128 = 340282366920938463463374607431768211455; // 128-bit unsigned integer.
    let k: isize = 9223372036854775807; // Pointer-sized signed integer (depends on architecture).
    let l: usize = 18446744073709551615; // Pointer-sized unsigned integer (depends on architecture).

    // Type inference.
    let m = 42; // The compiler infers `i32` by default.

    // Floating-point types.
    let n: f32 = 3.1; // 32-bit float.
    let o: f64 = 2.7; // 64-bit float (default for floats).

    // Boolean type.
    let p: bool = true;
    let q: bool = false;

    // Character type (Unicode scalar value).
    let r: char = 'a';
    let s: char = '😀'; // Unicode emoji.
    let t: char = '∞'; // Unicode symbol.

    // String types.
    let u: &str = "Hello"; // String slice.
    let v: String = String::from("World"); // Owned string.

    // Print all values.
    println!("Integers:");
    println!("i8: {}", a);
    println!("u8: {}", b);
    println!("i16: {}", c);
    println!("u16: {}", d);
    println!("i32: {}", e);
    println!("u32: {}", f);
    println!("i64: {}", g);
    println!("u64: {}", h);
    println!("i128: {}", i);
    println!("u128: {}", j);
    println!("isize: {}", k);
    println!("usize: {}", l);
    println!("inferred i32: {}", m);

    println!("\nFloating-point:");
    println!("f32: {}", n);
    println!("f64: {}", o);

    println!("\nBooleans:");
    println!("true: {}", p);
    println!("false: {}", q);

    println!("\nCharacters:");
    println!("ASCII: {}", r);
    println!("Emoji: {}", s);
    println!("Symbol: {}", t);

    println!("\nStrings:");
    println!("String slice: {}", u);
    println!("Owned string: {}", v);

    // Type operations:
    println!("\nType operations:");
    println!(
        "Integer addition: {} + {} = {}",
        a,
        100,
        a.wrapping_add(100)
    ); // Using wrapping_add to avoid overflow panic.
    println!("Float multiplication: {} * {} = {}", n, o, (n as f64) * o);
    println!("Boolean AND: {} && {} = {}", p, q, p && q);
    println!("Boolean OR: {} || {} = {}", p, q, p || q);
    println!(
        "String concatenation: {} + {} = {}",
        u,
        v,
        u.to_string() + &v
    );
}

Compound Data Types: Tuples and Arrays

Rust by example - tuples Rust by example - array

Compound types can group multiple values into one type. Rust has two primitive compound types: tuples and arrays.

TypeExamples
Tupleslet tup: (i32, f64, u8) = (500, 6.4, 1);. Access via let five_hundred = x.0;. Destructuring via let (x, y, z) = tup;.
Arrayslet a: [i32; 5] = [1, 2, 3, 4, 5]; allocated on the stack. Access via let first = a[0];.

Both are fixed length. A Vector is a similar collection type provided by the standard library that is allowed to grow or shrink in size.

The following provides examples of tuples and arrays:

/// Demonstrates the use of tuples and arrays in Rust, including their
/// declaration, access, destructuring, iteration, and mutation.
fn main() {
    println!("=== TUPLES ===");

    // Tuple with mixed types:
    // Tuples are fixed-size collections of values of potentially different
    // types.
    let person: (String, i32, bool) = (String::from("Alice"), 30, true);

    // Access tuple elements by index:
    // Tuple elements are accessed using a dot followed by the index
    // (starting from 0).
    println!("Name: {}", person.0);
    println!("Age: {}", person.1);
    println!("Active: {}", person.2);

    // Destructure a tuple:
    // Tuple elements can be extracted into separate variables
    // using destructuring.
    let (name, age, active) = person;
    println!(
        "Destructured - Name: {}, Age: {}, Active: {}",
        name, age, active
    );

    // Nested tuples:
    // Tuples can contain other tuples, allowing for complex data structures.
    let complex_data = (("Coordinates", (10.5, 20.8)), 42, [1, 2, 3]);
    println!(
        "Nested tuple access: {}, {}",
        (complex_data.0).0,
        (complex_data.0).1.0
    );

    // Unit (empty tuple).
    // The unit type `()` is a special tuple with no elements.
    let empty: () = ();
    println!("Empty tuple: {:?}", empty);

    // Tuple with a single element:
    // A single-element tuple requires a trailing comma to distinguish it from a
    // parenthesized expression.
    let single = (42,); // Note the comma.
    println!("Single element tuple: {:?}", single);

    // Functions with tuples.
    // Tuples can be passed to and returned from functions.
    fn swap_tuple(tuple: (i32, i32)) -> (i32, i32) {
        (tuple.1, tuple.0)
    }

    let original = (10, 20);
    let swapped = swap_tuple(original);
    println!("\nOriginal tuple: {:?}", original);
    println!("Swapped tuple: {:?}", swapped);

    println!("\n=== ARRAYS ===");

    // Fixed-size array with explicit type:
    // Arrays are fixed-size collections of elements of the same type.
    let numbers: [i32; 5] = [1, 2, 3, 4, 5];

    // Array with repeated values:
    // Arrays can be initialized with a repeated value
    // using the `[value; size]` syntax.
    let _zeros = [0; 10]; // Creates [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].

    // Array elements are accessed using square brackets
    // and the index (starting from 0).
    println!("First element: {}", numbers[0]);
    println!("Last element: {}", numbers[4]);

    // The `len()` method returns the number of elements in the array.
    println!("Array length: {}", numbers.len());

    // Slices from an array:
    // Slices provide a view into a contiguous sequence of elements in an array.
    let slice = &numbers[1..4]; // [2, 3, 4].
    println!("Slice: {:?}", slice);

    // Array of tuples:
    // Arrays can contain tuples, allowing for structured data within an array.
    let pairs: [(i32, &str); 3] = [(1, "one"), (2, "two"), (3, "three")];

    // Iterating over an array:
    // The `iter()` method provides an iterator over the array elements.
    println!("Iterating over array:");
    for num in numbers.iter() {
        println!("  Value: {}", num);
    }

    // The `enumerate()` method provides both the index
    // and the value for each element.
    println!("Iterating with index:");
    for (i, num) in numbers.iter().enumerate() {
        println!("  numbers[{}] = {}", i, num);
    }

    // Iterating over an array of tuples allows access
    // to both parts of each tuple.
    println!("Iterating over array of tuples:");
    for (number, name) in pairs.iter() {
        println!("  {} is written as {}", number, name);
    }

    // Multi-dimensional array:
    // Arrays can be nested to create multi-dimensional arrays.
    let matrix: [[i32; 3]; 2] = [[1, 2, 3], [4, 5, 6]];

    println!("Multi-dimensional array:");
    for row in matrix.iter() {
        println!("  {:?}", row);
    }

    // Arrays can be mutated if declared with `mut`.
    let mut mutable_array = [1, 2, 3, 4, 5];
    mutable_array[2] = 99;
    println!("Mutated array: {:?}", mutable_array);
}

Type Aliases

Use the type keyword to declare type aliases: type Kilometers = i32;.

Related Topics

See also:

  • Enums.
    • Option.
    • Result.
  • Slices.
  • Strings.
  • Structs.
  • Vectors.
  • Data Structures.