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.