Rust Standard Library Cookbook
上QQ阅读APP看书,第一时间看更新

How to do it...

  1. In the folder src/bin, create a file called iterator.rs.
  2. Add the following code, and run it with cargo run --bin iterator:
1   fn main() {
2 let names = vec!["Joe", "Miranda", "Alice"];
3 // Iterators can be accessed in many ways.
4 // Nearly all collections implement .iter() for this purpose
5 let mut iter = names.iter();
6 // A string itself is not iterable, but its characters are
7 let mut alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars();
8 // Ranges are also (limited) iterators
9 let nums = 0..10;
10 // You can even create infinite iterators!
11 let all_nums = 0..;
12
13 // As the name says, you can iterate over iterators
14 // This will consume the iterator
15 for num in nums {
16 print!("{} ", num);
17 }
18 // nums is no longer usable
19 println!();
20
21 // Get the index of the current item
22 for (index, letter) in "abc".chars().enumerate() {
23 println!("#{}. letter in the alphabet: {}", index + 1,
letter);
24 }
  1. Access individual items:
26    // going through an iterator, step by step
27 if let Some(name) = iter.next() {
28 println!("First name: {}", name);
29 }
30 if let Some(name) = iter.next() {
31 println!("Second name: {}", name);
32 }
33 if let Some(name) = iter.next() {
34 println!("Third name: {}", name);
35 }
36 if iter.next().is_none() {
37 println!("No names left");
38 }
39
40 // Arbitrary access to an item in the iterator
41 let letter = alphabet.nth(3);
42 if let Some(letter) = letter {
43 println!("the fourth letter in the alphabet is: {}",
letter);
44 }
45 // This works by consuming all items up to a point
46 let current_first = alphabet.nth(0);
47 if let Some(current_first) = current_first {
48 // This will NOT print 'A'
49 println!(
50 "The first item in the iterator is currently: {}",
51 current_first
52 );
53 }
54 let current_first = alphabet.nth(0);
55 if let Some(current_first) = current_first {
56 println!(
57 "The first item in the iterator is currently: {}",
58 current_first
59 );
60 }
61
62 // Accessing the last item; This will
63 // consume the entire iterator
64 let last_letter = alphabet.last();
65 if let Some(last_letter) = last_letter {
66 println!("The last letter of the alphabet is: {}",
last_letter);
67 }
  1. Collect the iterator into a collection:
69    // Collect iterators into collections
70 // This requires an anotation of which collection we want
71 // The following two are equivalent:
72 let nums: Vec<_> = (1..10).collect();
73 println!("nums: {:?}", nums);
74 let nums = (1..10).collect::<Vec<_>>();
75 println!("nums: {:?}", nums)
  1. Change which items are being iterated over:
79    // Taking only the first n items
80 // This is often used to make an infinite iterator finite
81 let nums: Vec<_> = all_nums.take(5).collect();
82 println!("The first five numbers are: {:?}", nums);
83
84 // Skip the first few items
85 let nums: Vec<_> = (0..11).skip(2).collect();
86 println!("The last 8 letters in a range from zero to 10:
{:?}", nums);
87
88 // take and skip accept predicates in the form of
89 // take_while and skip_while
90 let nums: Vec<_> = (0..).take_while(|x| x * x <
50).collect();
91 println!(
92 "All positive numbers that are less than 50 when squared:
93 {:?}", nums
94 );
95
96 // This is useful to filter an already sorted vector
97 let names = ["Alfred", "Andy", "Jose", "Luke"];
98 let names: Vec<_> = names.iter().skip_while(|x|
x.starts_with('A')).collect();
99 println!("Names that don't start with 'A': {:?}", names);
100
101 // Filtering iterators
102 let countries = [
103 "U.S.A.",
"Germany",
"France",
"Italy",
"India",
"Pakistan",
"Burma",
104 ];
105 let countries_with_i: Vec<_> = countries
106 .iter()
107 .filter(|country| country.contains('i'))
108 .collect();
109 println!(
110 "Countries containing the letter 'i': {:?}",
111 countries_with_i
112 );
  1. Check if an iterator contains an element:
116   // Find the first element that satisfies a condition
117 if let Some(country) = countries.iter().find(|country|
118 country.starts_with('I')) {
119 println!("First country starting with the letter 'I':
{}", country);
}
120
121 // Don't get the searched item but rather its index
122 if let Some(pos) = countries
123 .iter()
124 .position(|country| country.starts_with('I'))
125 {
126 println!("It's index is: {}", pos);
127 }
128
129 // Check if at least one item satisfies a condition
130 let are_any = countries.iter().any(|country| country.len() ==
5);
131 println!(
132 "Is there at least one country that has exactly five
letters? {}",
133 are_any
134 );
135
136 // Check if ALL items satisfy a condition
137 let are_all = countries.iter().all(|country| country.len() ==
5);
138 println!("Do all countries have exactly five letters? {}",
are_all);
  1. Useful operations for numeric items:
141   let sum: i32 = (1..11).sum();
142 let product: i32 = (1..11).product();
143 println!(
144 "When operating on the first ten positive numbers\n\
145 their sum is {} and\n\
146 their product is {}.",
147 sum, product
148 );
149
150 let max = (1..11).max();
151 let min = (1..11).min();
152 if let Some(max) = max {
153 println!("They have a highest number, and it is {}", max);
154 }
155 if let Some(min) = min {
156 println!("They have a smallest number, and it is {}", min);
157 }
  1. Combine iterators:
161   // Combine an iterator with itself, making it infinite
162 // When it reaches its end, it starts again
163 let some_numbers: Vec<_> = (1..4).cycle().take(10).collect();
164 // Reader exercise: Try to guess what this will print
165 println!("some_numbers: {:?}", some_numbers);
166
167 // Combine two iterators by putting them after another
168 let some_numbers: Vec<_> = (1..4).chain(10..14).collect();
169 println!("some_numbers: {:?}", some_numbers);
170
171 // Zip two iterators together by grouping their first items
172 // together, their second items together, etc.
173 let swiss_post_codes = [8957, 5000, 5034];
174 let swiss_towns = ["Spreitenbach", "Aarau", "Suhr"];
175 let zipped: Vec<_> =
swiss_post_codes.iter().zip(swiss_towns.iter()).collect();
176 println!("zipped: {:?}", zipped);
177
178 // Because zip is lazy, you can use two infine ranges
179 let zipped: Vec<_> = (b'A'..)
180 .zip(1..)
181 .take(10)
182 .map(|(ch, num)| (ch as char, num))
183 .collect();
184 println!("zipped: {:?}", zipped);
  1. Apply functions to all items:
188   // Change the items' types
189 let numbers_as_strings: Vec<_> = (1..11).map(|x|
x.to_string()).collect();
190 println!("numbers_as_strings: {:?}", numbers_as_strings);
191
192 // Access all items
193 println!("First ten squares:");
194 (1..11).for_each(|x| print!("{} ", x));
195 println!();
196
197 // filter and map items at the same time!
198 let squares: Vec<_> = (1..50)
199 .filter_map(|x| if x % 3 == 0 { Some(x * x) } else { None })
200 .collect();
201 println!(
202 "Squares of all numbers under 50 that are divisible by 3:
203 {:?}", squares
204 );
  1. The real strength of iterators comes from combining them:
208   // Retrieve the entire alphabet in lower and uppercase:
209 let alphabet: Vec<_> = (b'A' .. b'z' + 1) // Start as u8
210 .map(|c| c as char) // Convert all to chars
211 .filter(|c| c.is_alphabetic()) // Filter only alphabetic chars
212 .collect(); // Collect as Vec<char>
213 println!("alphabet: {:?}", alphabet);
214 }