Skip to content

Commit e256dd3

Browse files
committed
06: iterators
1 parent 84ebeea commit e256dd3

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ path = "content/lessons/06_closures_iterators/closures_capturing.rs"
8888
[[bin]]
8989
name = "06_closures_fun"
9090
path = "content/lessons/06_closures_iterators/closures_fun.rs"
91+
[[bin]]
92+
name = "06_iterator_exhaustion"
93+
path = "content/lessons/06_closures_iterators/iterator_exhaustion.rs"
9194

9295
[[bin]]
9396
name = "07_box"

content/lessons/06_closures_iterators/index.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,21 @@ More examples will be seen when working with iterators.
5757
In Rust, there is no hierarchy of types for collections (because there is no inheritance in general).
5858
Instead, what makes a collection is that it can be iterated over.
5959

60+
A usual way in Rust to perform an iteration over something, be it a range of values or items in a collection, is creating a (lazy) iterator over it and transforming it using *iterator adaptors*. For example, if `T: Iterator`, then `T::map()` creates a `Map<T>` adaptor. Once a final iterator is created, it has to be actually activated, which is most commonly done by:
61+
- exhausting it with the `for` loop,
62+
- manually iterating over it using `next()` calls,
63+
- collecting its contents into inferred collection (`collect()`),
64+
- consuming it with a *consuming adaptor* (e.g., `sum()`, `count`),
65+
66+
{{ include_code_sample(path="lessons/06_closures_iterators/iterator_exhaustion.rs", language="rust") }}
67+
68+
69+
Iterators are highly optimised, so they are high-level code that compiles down to simple and optimised machine code (intended as _zero-cost abstractions_).
70+
6071
We'll go through the official [docs](https://doc.rust-lang.org/stable/std/iter/).
61-
Most methods are defined in the [Iterator trait](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html).
72+
- Most methods are defined in the [Iterator trait](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html).
73+
- [IntoIterator](https://doc.rust-lang.org/stable/std/iter/trait.IntoIterator.html) is also worth noting, because it makes types work with the `for` loop.
74+
- For completeness, there is [FromIterator](https://doc.rust-lang.org/stable/std/iter/trait.FromIterator.html), which is required for `collect()` to work.
6275

6376
# Reading
6477

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use std::collections::HashSet;
2+
3+
fn main() {
4+
// Various ways to create a String.
5+
let mut strings = [
6+
String::new(),
7+
String::from("a"),
8+
"b".into(),
9+
"c".to_owned(),
10+
"d".to_string(),
11+
"e".chars().collect(),
12+
];
13+
14+
// `iter()` is a usual method that creates an iterator over immutable references to the collection's items.
15+
let _all_len_0_or_1 = strings
16+
.iter()
17+
.filter(|s| !s.is_empty())
18+
.all(|s| s.len() == 1);
19+
20+
// `iter_mut()` is a usual method that creates an iterator over mutable references to the collection's items.
21+
for s in strings.iter_mut().map_while(|s| match s.as_str() {
22+
"c" => None,
23+
_ => Some(s),
24+
}) {
25+
*s = s.replace("b", "aba");
26+
}
27+
28+
// This is equivalent code.
29+
// `for` is usually more idiomatic, but `for_each` is sometimes cleaner and sometimes faster.
30+
strings
31+
.iter_mut()
32+
.map_while(|s| match s.as_str() {
33+
"c" => None,
34+
_ => Some(s),
35+
})
36+
.for_each(|s| *s = s.replace("b", "aba"));
37+
38+
// `into_iter()` is a method from `IntoIterator` trait that converts a collection to an iterator
39+
let mut empty_strings_iter = strings.into_iter().map(|mut s| {
40+
s.clear();
41+
s
42+
});
43+
44+
// This is a set of empty Strings...
45+
let empty_strings_set = empty_strings_iter.clone().collect::<HashSet<_>>();
46+
47+
// And this is a Vec of immutable references to empty Strings.
48+
let empty_string_refs_vec = empty_strings_set.iter().collect::<Vec<_>>();
49+
50+
// equivalent to `empty_string_refs_vec.into_iter()`
51+
for s in empty_string_refs_vec {
52+
println!("{}", s)
53+
}
54+
55+
while let Some(s) = empty_strings_iter.next_back() {
56+
assert!(s.is_empty());
57+
}
58+
}

0 commit comments

Comments
 (0)