+6
-2
.rustlings-state.txt
+6
-2
.rustlings-state.txt
+2
exercises/19_smart_pointers/arc1.rs
+2
exercises/19_smart_pointers/arc1.rs
···
24
24
25
25
// TODO: Define `shared_numbers` by using `Arc`.
26
26
// let shared_numbers = ???;
27
+
let shared_numbers = Arc::new(numbers);
27
28
28
29
let mut join_handles = Vec::new();
29
30
30
31
for offset in 0..8 {
31
32
// TODO: Define `child_numbers` using `shared_numbers`.
32
33
// let child_numbers = ???;
34
+
let child_numbers = Arc::clone(&shared_numbers);
33
35
34
36
let handle = thread::spawn(move || {
35
37
let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();
+3
-3
exercises/19_smart_pointers/box1.rs
+3
-3
exercises/19_smart_pointers/box1.rs
···
12
12
// TODO: Use a `Box` in the enum definition to make the code compile.
13
13
#[derive(PartialEq, Debug)]
14
14
enum List {
15
-
Cons(i32, List),
15
+
Cons(i32, Box<List>),
16
16
Nil,
17
17
}
18
18
19
19
// TODO: Create an empty cons list.
20
20
fn create_empty_list() -> List {
21
-
todo!()
21
+
List::Nil
22
22
}
23
23
24
24
// TODO: Create a non-empty cons list.
25
25
fn create_non_empty_list() -> List {
26
-
todo!()
26
+
List::Cons(1, Box::new(List::Nil))
27
27
}
28
28
29
29
fn main() {
+3
-3
exercises/19_smart_pointers/cow1.rs
+3
-3
exercises/19_smart_pointers/cow1.rs
···
39
39
let mut input = Cow::from(&vec);
40
40
abs_all(&mut input);
41
41
// TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
42
-
assert!(matches!(input, todo!()));
42
+
assert!(matches!(input, Cow::Borrowed(_)));
43
43
}
44
44
45
45
#[test]
···
52
52
let mut input = Cow::from(vec);
53
53
abs_all(&mut input);
54
54
// TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
55
-
assert!(matches!(input, todo!()));
55
+
assert!(matches!(input, Cow::Owned(_)));
56
56
}
57
57
58
58
#[test]
···
64
64
let mut input = Cow::from(vec);
65
65
abs_all(&mut input);
66
66
// TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
67
-
assert!(matches!(input, todo!()));
67
+
assert!(matches!(input, Cow::Owned(_)));
68
68
}
69
69
}
+6
-3
exercises/19_smart_pointers/rc1.rs
+6
-3
exercises/19_smart_pointers/rc1.rs
···
60
60
jupiter.details();
61
61
62
62
// TODO
63
-
let saturn = Planet::Saturn(Rc::new(Sun));
63
+
let saturn = Planet::Saturn(Rc::clone(&sun));
64
64
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
65
65
saturn.details();
66
66
67
67
// TODO
68
-
let uranus = Planet::Uranus(Rc::new(Sun));
68
+
let uranus = Planet::Uranus(Rc::clone(&sun));
69
69
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
70
70
uranus.details();
71
71
72
72
// TODO
73
-
let neptune = Planet::Neptune(Rc::new(Sun));
73
+
let neptune = Planet::Neptune(Rc::clone(&sun));
74
74
println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
75
75
neptune.details();
76
76
···
92
92
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
93
93
94
94
// TODO
95
+
drop(earth);
95
96
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
96
97
97
98
// TODO
99
+
drop(venus);
98
100
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
99
101
100
102
// TODO
103
+
drop(mercury);
101
104
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
102
105
103
106
assert_eq!(Rc::strong_count(&sun), 1);
+43
-2
solutions/19_smart_pointers/arc1.rs
+43
-2
solutions/19_smart_pointers/arc1.rs
···
1
+
// In this exercise, we are given a `Vec` of `u32` called `numbers` with values
2
+
// ranging from 0 to 99. We would like to use this set of numbers within 8
3
+
// different threads simultaneously. Each thread is going to get the sum of
4
+
// every eighth value with an offset.
5
+
//
6
+
// The first thread (offset 0), will sum 0, 8, 16, …
7
+
// The second thread (offset 1), will sum 1, 9, 17, …
8
+
// The third thread (offset 2), will sum 2, 10, 18, …
9
+
// …
10
+
// The eighth thread (offset 7), will sum 7, 15, 23, …
11
+
//
12
+
// Each thread should own a reference-counting pointer to the vector of
13
+
// numbers. But `Rc` isn't thread-safe. Therefore, we need to use `Arc`.
14
+
//
15
+
// Don't get distracted by how threads are spawned and joined. We will practice
16
+
// that later in the exercises about threads.
17
+
18
+
// Don't change the lines below.
19
+
#![forbid(unused_imports)]
20
+
use std::{sync::Arc, thread};
21
+
1
22
fn main() {
2
-
// DON'T EDIT THIS SOLUTION FILE!
3
-
// It will be automatically filled after you finish the exercise.
23
+
let numbers: Vec<_> = (0..100u32).collect();
24
+
25
+
let shared_numbers = Arc::new(numbers);
26
+
// ^^^^^^^^^^^^^^^^^
27
+
28
+
let mut join_handles = Vec::new();
29
+
30
+
for offset in 0..8 {
31
+
let child_numbers = Arc::clone(&shared_numbers);
32
+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
33
+
34
+
let handle = thread::spawn(move || {
35
+
let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();
36
+
println!("Sum of offset {offset} is {sum}");
37
+
});
38
+
39
+
join_handles.push(handle);
40
+
}
41
+
42
+
for handle in join_handles.into_iter() {
43
+
handle.join().unwrap();
44
+
}
4
45
}
+45
-2
solutions/19_smart_pointers/box1.rs
+45
-2
solutions/19_smart_pointers/box1.rs
···
1
+
// At compile time, Rust needs to know how much space a type takes up. This
2
+
// becomes problematic for recursive types, where a value can have as part of
3
+
// itself another value of the same type. To get around the issue, we can use a
4
+
// `Box` - a smart pointer used to store data on the heap, which also allows us
5
+
// to wrap a recursive type.
6
+
//
7
+
// The recursive type we're implementing in this exercise is the "cons list", a
8
+
// data structure frequently found in functional programming languages. Each
9
+
// item in a cons list contains two elements: The value of the current item and
10
+
// the next item. The last item is a value called `Nil`.
11
+
12
+
#[derive(PartialEq, Debug)]
13
+
enum List {
14
+
Cons(i32, Box<List>),
15
+
Nil,
16
+
}
17
+
18
+
fn create_empty_list() -> List {
19
+
List::Nil
20
+
}
21
+
22
+
fn create_non_empty_list() -> List {
23
+
List::Cons(42, Box::new(List::Nil))
24
+
}
25
+
1
26
fn main() {
2
-
// DON'T EDIT THIS SOLUTION FILE!
3
-
// It will be automatically filled after you finish the exercise.
27
+
println!("This is an empty cons list: {:?}", create_empty_list());
28
+
println!(
29
+
"This is a non-empty cons list: {:?}",
30
+
create_non_empty_list(),
31
+
);
32
+
}
33
+
34
+
#[cfg(test)]
35
+
mod tests {
36
+
use super::*;
37
+
38
+
#[test]
39
+
fn test_create_empty_list() {
40
+
assert_eq!(create_empty_list(), List::Nil);
41
+
}
42
+
43
+
#[test]
44
+
fn test_create_non_empty_list() {
45
+
assert_ne!(create_empty_list(), create_non_empty_list());
46
+
}
4
47
}
+67
-2
solutions/19_smart_pointers/cow1.rs
+67
-2
solutions/19_smart_pointers/cow1.rs
···
1
+
// This exercise explores the `Cow` (Clone-On-Write) smart pointer. It can
2
+
// enclose and provide immutable access to borrowed data and clone the data
3
+
// lazily when mutation or ownership is required. The type is designed to work
4
+
// with general borrowed data via the `Borrow` trait.
5
+
6
+
use std::borrow::Cow;
7
+
8
+
fn abs_all(input: &mut Cow<[i32]>) {
9
+
for ind in 0..input.len() {
10
+
let value = input[ind];
11
+
if value < 0 {
12
+
// Clones into a vector if not already owned.
13
+
input.to_mut()[ind] = -value;
14
+
}
15
+
}
16
+
}
17
+
1
18
fn main() {
2
-
// DON'T EDIT THIS SOLUTION FILE!
3
-
// It will be automatically filled after you finish the exercise.
19
+
// You can optionally experiment here.
20
+
}
21
+
22
+
#[cfg(test)]
23
+
mod tests {
24
+
use super::*;
25
+
26
+
#[test]
27
+
fn reference_mutation() {
28
+
// Clone occurs because `input` needs to be mutated.
29
+
let vec = vec![-1, 0, 1];
30
+
let mut input = Cow::from(&vec);
31
+
abs_all(&mut input);
32
+
assert!(matches!(input, Cow::Owned(_)));
33
+
}
34
+
35
+
#[test]
36
+
fn reference_no_mutation() {
37
+
// No clone occurs because `input` doesn't need to be mutated.
38
+
let vec = vec![0, 1, 2];
39
+
let mut input = Cow::from(&vec);
40
+
abs_all(&mut input);
41
+
assert!(matches!(input, Cow::Borrowed(_)));
42
+
// ^^^^^^^^^^^^^^^^
43
+
}
44
+
45
+
#[test]
46
+
fn owned_no_mutation() {
47
+
// We can also pass `vec` without `&` so `Cow` owns it directly. In this
48
+
// case, no mutation occurs (all numbers are already absolute) and thus
49
+
// also no clone. But the result is still owned because it was never
50
+
// borrowed or mutated.
51
+
let vec = vec![0, 1, 2];
52
+
let mut input = Cow::from(vec);
53
+
abs_all(&mut input);
54
+
assert!(matches!(input, Cow::Owned(_)));
55
+
// ^^^^^^^^^^^^^
56
+
}
57
+
58
+
#[test]
59
+
fn owned_mutation() {
60
+
// Of course this is also the case if a mutation does occur (not all
61
+
// numbers are absolute). In this case, the call to `to_mut()` in the
62
+
// `abs_all` function returns a reference to the same data as before.
63
+
let vec = vec![-1, 0, 1];
64
+
let mut input = Cow::from(vec);
65
+
abs_all(&mut input);
66
+
assert!(matches!(input, Cow::Owned(_)));
67
+
// ^^^^^^^^^^^^^
68
+
}
4
69
}
+102
-2
solutions/19_smart_pointers/rc1.rs
+102
-2
solutions/19_smart_pointers/rc1.rs
···
1
+
// In this exercise, we want to express the concept of multiple owners via the
2
+
// `Rc<T>` type. This is a model of our solar system - there is a `Sun` type and
3
+
// multiple `Planet`s. The planets take ownership of the sun, indicating that
4
+
// they revolve around the sun.
5
+
6
+
use std::rc::Rc;
7
+
8
+
#[derive(Debug)]
9
+
struct Sun;
10
+
11
+
#[derive(Debug)]
12
+
enum Planet {
13
+
Mercury(Rc<Sun>),
14
+
Venus(Rc<Sun>),
15
+
Earth(Rc<Sun>),
16
+
Mars(Rc<Sun>),
17
+
Jupiter(Rc<Sun>),
18
+
Saturn(Rc<Sun>),
19
+
Uranus(Rc<Sun>),
20
+
Neptune(Rc<Sun>),
21
+
}
22
+
23
+
impl Planet {
24
+
fn details(&self) {
25
+
println!("Hi from {self:?}!");
26
+
}
27
+
}
28
+
1
29
fn main() {
2
-
// DON'T EDIT THIS SOLUTION FILE!
3
-
// It will be automatically filled after you finish the exercise.
30
+
// You can optionally experiment here.
31
+
}
32
+
33
+
#[cfg(test)]
34
+
mod tests {
35
+
use super::*;
36
+
37
+
#[test]
38
+
fn rc1() {
39
+
let sun = Rc::new(Sun);
40
+
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
41
+
42
+
let mercury = Planet::Mercury(Rc::clone(&sun));
43
+
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
44
+
mercury.details();
45
+
46
+
let venus = Planet::Venus(Rc::clone(&sun));
47
+
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
48
+
venus.details();
49
+
50
+
let earth = Planet::Earth(Rc::clone(&sun));
51
+
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
52
+
earth.details();
53
+
54
+
let mars = Planet::Mars(Rc::clone(&sun));
55
+
println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
56
+
mars.details();
57
+
58
+
let jupiter = Planet::Jupiter(Rc::clone(&sun));
59
+
println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
60
+
jupiter.details();
61
+
62
+
let saturn = Planet::Saturn(Rc::clone(&sun));
63
+
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
64
+
saturn.details();
65
+
66
+
// TODO
67
+
let uranus = Planet::Uranus(Rc::clone(&sun));
68
+
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
69
+
uranus.details();
70
+
71
+
// TODO
72
+
let neptune = Planet::Neptune(Rc::clone(&sun));
73
+
println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
74
+
neptune.details();
75
+
76
+
assert_eq!(Rc::strong_count(&sun), 9);
77
+
78
+
drop(neptune);
79
+
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
80
+
81
+
drop(uranus);
82
+
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
83
+
84
+
drop(saturn);
85
+
println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
86
+
87
+
drop(jupiter);
88
+
println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
89
+
90
+
drop(mars);
91
+
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
92
+
93
+
drop(earth);
94
+
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
95
+
96
+
drop(venus);
97
+
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
98
+
99
+
drop(mercury);
100
+
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
101
+
102
+
assert_eq!(Rc::strong_count(&sun), 1);
103
+
}
4
104
}