|
7 | 7 | // Strings are collections of characters, and they can be mutable or immutable. |
8 | 8 |
|
9 | 9 | fn main() { |
10 | | - // Example of a tuple |
| 10 | + println!("=== Compound Data Types in Rust ===\n"); |
| 11 | + |
| 12 | + // ===== TUPLES ===== |
| 13 | + println!("--- TUPLES ---"); |
| 14 | + |
| 15 | + // Basic tuple |
11 | 16 | let person: (&str, String, i32, f64, bool) = ("Alice", String::from("Bob"), 30, 5.5, false); |
12 | 17 | println!("Tuple: {:?}", person); |
13 | 18 | println!("Name1: {}, Name2: {}, Age: {}, Height: {}, Is Student: {}", person.0, person.1, person.2, person.3, person.4); |
14 | | - |
15 | | - // Example of an array |
16 | | - // {} represents a display format for arrays |
17 | | - // {?} is used to print the array in a debug format |
18 | | - // Arrays in Rust are fixed-size and must have a type specified |
| 19 | + |
| 20 | + // Tuple destructuring - unpacking values into separate variables |
| 21 | + let (name1, name2, age, height, is_student) = person; |
| 22 | + println!("\nDestructured tuple:"); |
| 23 | + println!(" name1: {}", name1); |
| 24 | + println!(" name2: {}", name2); |
| 25 | + println!(" age: {}", age); |
| 26 | + println!(" height: {}", height); |
| 27 | + println!(" is_student: {}", is_student); |
| 28 | + |
| 29 | + // Unit type - empty tuple (used when no value is returned) |
| 30 | + let unit: () = (); |
| 31 | + println!("\nUnit type: {:?} (size: {} bytes)", unit, std::mem::size_of_val(&unit)); |
| 32 | + |
| 33 | + // Nested tuples |
| 34 | + let nested: ((i32, i32), (i32, i32)) = ((1, 2), (3, 4)); |
| 35 | + println!("Nested tuple: {:?}", nested); |
| 36 | + println!("Access nested: ({}, {})", nested.0.0, nested.1.1); |
| 37 | + |
| 38 | + // Tuples as function return values |
| 39 | + let coords = get_coordinates(); |
| 40 | + println!("Function returned tuple: {:?}", coords); |
| 41 | + |
| 42 | + // ===== ARRAYS ===== |
| 43 | + println!("\n--- ARRAYS ---"); |
| 44 | + |
| 45 | + // Basic array |
19 | 46 | let numbers: [i32; 5] = [1, 2, 3, 4, 5]; |
20 | 47 | println!("Array: {:?}", numbers); |
21 | | - |
22 | | - // Example of an array of strings |
| 48 | + |
| 49 | + // Array initialization shortcut - [value; count] |
| 50 | + let zeros: [i32; 5] = [0; 5]; // Creates [0, 0, 0, 0, 0] |
| 51 | + let threes: [i32; 10] = [3; 10]; // Creates 10 threes |
| 52 | + println!("Array of zeros: {:?}", zeros); |
| 53 | + println!("Array of threes: {:?}", threes); |
| 54 | + |
| 55 | + // Array length and iteration |
| 56 | + println!("\nArray length: {}", numbers.len()); |
| 57 | + println!("Iterating over array:"); |
| 58 | + for (index, value) in numbers.iter().enumerate() { |
| 59 | + println!(" Index {}: {}", index, value); |
| 60 | + } |
| 61 | + |
| 62 | + // Mutable arrays |
| 63 | + let mut mutable_array = [1, 2, 3, 4, 5]; |
| 64 | + println!("\nOriginal array: {:?}", mutable_array); |
| 65 | + mutable_array[0] = 10; |
| 66 | + mutable_array[4] = 50; |
| 67 | + println!("Modified array: {:?}", mutable_array); |
| 68 | + |
| 69 | + // Multidimensional arrays |
| 70 | + let matrix: [[i32; 3]; 2] = [ |
| 71 | + [1, 2, 3], |
| 72 | + [4, 5, 6] |
| 73 | + ]; |
| 74 | + println!("\n2D array (matrix): {:?}", matrix); |
| 75 | + println!("Element at [1][2]: {}", matrix[1][2]); |
| 76 | + |
| 77 | + // Array of strings |
23 | 78 | let words: [&str; 3] = ["Rust", "is", "awesome"]; |
24 | | - println!("Words: {:?}", words); |
25 | | - // Accessing elements in an array |
| 79 | + println!("\nWords: {:?}", words); |
26 | 80 | println!("First word: {}", words[0]); |
27 | 81 | println!("Second word: {}", words[1]); |
28 | 82 | println!("Third word: {}", words[2]); |
| 83 | + |
| 84 | + // Note: Array bounds checking |
| 85 | + // Uncommenting the line below will cause a panic at runtime: |
| 86 | + // println!("Out of bounds: {}", words[10]); // PANIC! |
| 87 | + println!("\nNote: Accessing out-of-bounds index causes panic at runtime"); |
| 88 | + println!("Rust checks array bounds to prevent memory safety issues"); |
29 | 89 |
|
30 | | - |
31 | | - // Example of a slice |
32 | | - let slice1: &[i32] = &numbers[1..4]; |
33 | | - let slice2: &[i32] = &numbers[0..2]; |
34 | | - let slice3: &[i32] = &numbers[2..]; |
35 | | - let slice4: &[i32] = &numbers[..]; // Full slice of the array |
36 | | - let slice5: &[char] = &person.0.chars().collect::<Vec<char>>()[..]; // Slicing the characters of the name in the tuple |
37 | | - let slice6: &[char] = &person.1.chars().collect::<Vec<char>>()[..]; // Slicing the characters of the name in the tuple |
38 | | - println!("Slice1 of numbers: {:?}", slice1); |
39 | | - println!("Slice2 of numbers: {:?}", slice2); |
40 | | - println!("Slice3 of numbers: {:?}", slice3); |
41 | | - println!("Slice4 of numbers: {:?}", slice4); |
42 | | - println!("Slice5 of person name1: {:?}", slice5); |
43 | | - println!("Slice6 of person name2: {:?}", slice6); |
44 | | - |
45 | | - // Example of a string |
| 90 | + // ===== SLICES ===== |
| 91 | + println!("\n--- SLICES ---"); |
| 92 | + |
| 93 | + let slice1: &[i32] = &numbers[1..4]; // Elements 1, 2, 3 |
| 94 | + let slice2: &[i32] = &numbers[0..2]; // Elements 0, 1 |
| 95 | + let slice3: &[i32] = &numbers[2..]; // From element 2 to end |
| 96 | + let slice4: &[i32] = &numbers[..3]; // From start to element 2 |
| 97 | + let slice5: &[i32] = &numbers[..]; // Full slice of the array |
| 98 | + |
| 99 | + println!("Original array: {:?}", numbers); |
| 100 | + println!("Slice [1..4]: {:?}", slice1); |
| 101 | + println!("Slice [0..2]: {:?}", slice2); |
| 102 | + println!("Slice [2..]: {:?}", slice3); |
| 103 | + println!("Slice [..3]: {:?}", slice4); |
| 104 | + println!("Slice [..]: {:?}", slice5); |
| 105 | + |
| 106 | + // Slice length |
| 107 | + println!("Slice1 length: {}", slice1.len()); |
| 108 | + |
| 109 | + // ===== STRINGS ===== |
| 110 | + println!("\n--- STRINGS ---"); |
| 111 | + |
| 112 | + // String vs &str |
| 113 | + // String: growable, heap-allocated, mutable, owned |
| 114 | + // &str: string slice, fixed size, immutable, borrowed (view into string) |
| 115 | + |
46 | 116 | let mut greeting: String = String::from("Hello, "); |
47 | 117 | greeting.push_str("World!"); |
48 | | - println!("Greeting: {}", greeting); |
49 | | - |
50 | | - // Strings vs String slices (&str) |
51 | | - // String is a growable, heap-allocated data structure [growable, mutable, owned] |
52 | | - // &str is a string slice, which is a view into a string [fixed size, immutable, borrowed] |
53 | | - let greeting_slice: &str = &greeting[..]; |
54 | | - println!("Greeting slice: {}", greeting_slice); |
55 | | - |
56 | | - // mut is used to make a variable mutable |
| 118 | + println!("String: {}", greeting); |
| 119 | + |
| 120 | + // String methods |
| 121 | + println!("\nString methods:"); |
| 122 | + println!(" Length: {}", greeting.len()); |
| 123 | + println!(" Is empty: {}", greeting.is_empty()); |
| 124 | + println!(" Bytes: {}", greeting.bytes().count()); |
| 125 | + println!(" Contains 'World': {}", greeting.contains("World")); |
| 126 | + |
| 127 | + // String indexing - IMPORTANT: Cannot directly index strings! |
| 128 | + // This would NOT work: greeting[0] |
| 129 | + // Strings are UTF-8 encoded, so indexing by byte position isn't safe |
| 130 | + println!("\nString characters (using .chars()):"); |
| 131 | + for (i, ch) in greeting.chars().enumerate() { |
| 132 | + println!(" Position {}: {}", i, ch); |
| 133 | + } |
| 134 | + |
| 135 | + // String slicing (careful with UTF-8!) |
| 136 | + let greeting_slice: &str = &greeting[0..5]; // "Hello" |
| 137 | + println!("\nString slice [0..5]: {}", greeting_slice); |
| 138 | + |
| 139 | + // String concatenation methods |
| 140 | + let s1 = String::from("Hello"); |
| 141 | + let s2 = String::from("World"); |
| 142 | + |
| 143 | + // Method 1: + operator (takes ownership of s1) |
| 144 | + let s3 = s1 + " " + &s2; // s1 is moved here |
| 145 | + println!("\nConcatenation with +: {}", s3); |
| 146 | + |
| 147 | + // Method 2: format! macro (doesn't take ownership) |
| 148 | + let s4 = String::from("Rust"); |
| 149 | + let s5 = String::from("Programming"); |
| 150 | + let s6 = format!("{} {}", s4, s5); |
| 151 | + println!("Concatenation with format!: {}", s6); |
| 152 | + println!("s4 still valid: {}", s4); // s4 not moved |
| 153 | + |
| 154 | + // Mutable string operations |
57 | 155 | let mut mutable_string: String = String::from("Mutable String"); |
| 156 | + println!("\nOriginal: {}", mutable_string); |
| 157 | + |
58 | 158 | mutable_string.push_str(" - Now I can change it!"); |
59 | | - println!("Mutable String: {}", mutable_string); |
| 159 | + println!("After push_str: {}", mutable_string); |
| 160 | + |
| 161 | + mutable_string.push('!'); |
| 162 | + println!("After push (char): {}", mutable_string); |
| 163 | + |
| 164 | + // String to bytes |
| 165 | + println!("\nString as bytes: {:?}", greeting.as_bytes()); |
| 166 | + |
| 167 | + // ===== TUPLE STRUCTS ===== |
| 168 | + println!("\n--- TUPLE STRUCTS ---"); |
| 169 | + |
| 170 | + // Tuple structs are named tuples |
| 171 | + struct Color(i32, i32, i32); |
| 172 | + struct Point(i32, i32); |
| 173 | + |
| 174 | + let black = Color(0, 0, 0); |
| 175 | + let origin = Point(0, 0); |
| 176 | + |
| 177 | + println!("Color RGB: ({}, {}, {})", black.0, black.1, black.2); |
| 178 | + println!("Point: ({}, {})", origin.0, origin.1); |
| 179 | + |
| 180 | + // ===== NESTED STRUCTURES ===== |
| 181 | + println!("\n--- NESTED STRUCTURES ---"); |
| 182 | + |
| 183 | + // Nested arrays and tuples |
| 184 | + let nested_array: [[i32; 2]; 3] = [[1, 2], [3, 4], [5, 6]]; |
| 185 | + println!("Nested array: {:?}", nested_array); |
| 186 | + |
| 187 | + let complex: (String, [i32; 3], (bool, f64)) = ( |
| 188 | + String::from("Complex"), |
| 189 | + [1, 2, 3], |
| 190 | + (true, 3.14) |
| 191 | + ); |
| 192 | + println!("Complex tuple: ({}, {:?}, {:?})", complex.0, complex.1, complex.2); |
| 193 | + |
| 194 | + println!("\n=== End of Compound Data Types Demo ==="); |
| 195 | +} |
| 196 | + |
| 197 | +// Helper function demonstrating tuple as return type |
| 198 | +fn get_coordinates() -> (f64, f64) { |
| 199 | + (10.5, 20.3) |
60 | 200 | } |
0 commit comments