Data Types
Scalar Data Types
Rust has several categories of primitive types: integers, floating-point numbers, Booleans, unicode characters, 'Unit', and 'Never'.
Type Family | Types | Examples |
---|---|---|
Signed Integers | i8 ⮳, i16 ⮳, i32 ⮳, i64 ⮳, i128 ⮳, isize ⮳. | -8i8 , -32i32 . |
Unsigned Integers | u8 ⮳, u16 ⮳, u32 ⮳, u64 ⮳, u128 ⮳, usize ⮳. | 6u8 . |
Floating point | f32 ⮳, f64 ⮳. | 0.15 . |
Boolean | bool ⮳. | true , false . |
Unicode Character | char ⮳ | let z: char = 'ℤ'; |
Unit | unit ⮳. | 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. |
Never | never ⮳. | ! 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
Compound types can group multiple values into one type. Rust has two primitive compound types: tuples and arrays.
Type | Examples |
---|---|
Tuples | let tup: (i32, f64, u8) = (500, 6.4, 1); . Access via let five_hundred = x.0; . Destructuring via let (x, y, z) = tup; . |
Arrays | let 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.