Home Rust Tutorial: Data Types in Rust Programming Language

Tutorial: Data Types in Rust Programming Language

Rust is a statically typed language, which means that the type of every variable must be known at compile time.

Rust provides a rich set of data types to handle different kinds of values and supports type inference, making it powerful and easy to use.

This tutorial covers:

1. Primitive Data Types

1.1 Integers

Rust supports signed (i) and unsigned (u) integers of various sizes:

  • Signed: i8, i16, i32, i64, i128, isize
  • Unsigned: u8, u16, u32, u64, u128, usize

Example: Integer Types

fn main() {
    let x: i32 = -10;  // Signed 32-bit integer
    let y: u32 = 42;   // Unsigned 32-bit integer
    let z = 1_000_000; // Type inferred as i32; underscores for readability

    println!("x: {}, y: {}, z: {}", x, y, z);
}

1.2 Floating-Point Numbers

Rust has two floating-point types:

  • f32: 32-bit floating point
  • f64: 64-bit floating point (default)

Example: Floating-Point Types

fn main() {
    let pi: f64 = 3.14159;  // Explicit 64-bit float
    let e = 2.718;          // Type inferred as f64

    println!("pi: {}, e: {}", pi, e);
}

1.3 Booleans

Booleans in Rust are represented by the bool type with values true or false.

Example: Booleans

fn main() {
    let is_active: bool = true;
    let is_logged_in = false; // Type inferred as bool

    println!("is_active: {}, is_logged_in: {}", is_active, is_logged_in);
}

1.4 Characters

The char type represents a single Unicode character.

Example: Characters

fn main() {
    let letter: char = 'A';
    let emoji = '😊';  // Rust supports Unicode characters

    println!("letter: {}, emoji: {}", letter, emoji);
}

2. Compound Data Types

2.1 Tuples

A tuple is a collection of values of different types. Tuples have a fixed length and can be deconstructed.

Example: Tuples

fn main() {
    let person: (&str, u32, f64) = ("Alice", 30, 5.5);
    let (name, age, height) = person; // Destructure tuple

    println!("Name: {}, Age: {}, Height: {}", name, age, height);

    // Access elements by index
    println!("Age: {}", person.1);
}

2.2 Arrays

Arrays in Rust have a fixed size and must contain elements of the same type.

Example: Arrays

fn main() {
    let numbers: [i32; 4] = [1, 2, 3, 4]; // Array of 4 i32 values
    let default_array = [0; 5];          // Array with 5 elements, all set to 0

    println!("First number: {}", numbers[0]);
    println!("Default array: {:?}", default_array);
}

3. Special Data Types

3.1 Strings

Rust has two string types:

  • String: A growable, heap-allocated string.
  • &str: A string slice, often used for string literals.

Example: Strings

fn main() {
    let name = String::from("Alice"); // Growable String
    let greeting: &str = "Hello";     // String slice

    println!("{}, {}!", greeting, name);
}

3.2 Slices

Slices are references to a contiguous sequence of elements in an array or a string.

Example: Slices

fn main() {
    let numbers = [1, 2, 3, 4, 5];
    let slice = &numbers[1..4]; // Slice from index 1 to 3

    println!("Slice: {:?}", slice);
}

3.3 Option

The Option type represents an optional value. It can be Some(T) (a value exists) or None.

Example: Option

fn main() {
    let value: Option<i32> = Some(10);
    let no_value: Option<i32> = None;

    match value {
        Some(v) => println!("Value: {}", v),
        None => println!("No value"),
    }

    match no_value {
        Some(v) => println!("Value: {}", v),
        None => println!("No value"),
    }
}

4. Type Annotations and Inference

Rust requires explicit type annotations in some cases, but often it can infer types.

Example: Type Inference

fn main() {
    let x = 42;        // Inferred as i32
    let y = 3.14;      // Inferred as f64
    let flag = true;   // Inferred as bool

    println!("x: {}, y: {}, flag: {}", x, y, flag);
}

Example: Explicit Annotations

fn main() {
    let x: i64 = 42;
    let y: f32 = 3.14;
    let flag: bool = true;

    println!("x: {}, y: {}, flag: {}", x, y, flag);
}

5. Practical Examples

5.1 Finding the Average of an Array

fn main() {
    let numbers = [1, 2, 3, 4, 5];
    let sum: i32 = numbers.iter().sum();
    let count = numbers.len();

    let average = sum as f32 / count as f32;

    println!("Average: {}", average);
}

5.2 Manipulating Strings

fn main() {
    let mut message = String::from("Hello");
    message.push('!');       // Add a character
    message.push_str(" Rust"); // Add a string

    println!("Message: {}", message);
}

5.3 Using Tuples and Arrays Together

fn main() {
    let student: (&str, [i32; 3]) = ("Alice", [90, 85, 88]);
    let (name, scores) = student;

    println!("Name: {}", name);
    println!("Scores: {:?}", scores);
}

6. Summary

Rust Data Types

  • Primitive Types: Integers, floats, booleans, and characters.
  • Compound Types: Tuples and arrays.
  • Special Types: Strings, slices, and Option.

Key Takeaways

  • Rust enforces type safety and encourages explicit type handling.
  • Compound types like tuples and arrays are essential for organizing data.
  • Special types like Option and slices provide powerful abstractions.

Understanding Rust's data types is fundamental to writing robust and efficient Rust programs.

You may also like