From c56888fcf5d83d16b6d63141ea32271cc4b96538 Mon Sep 17 00:00:00 2001 From: Arcadie Date: Tue, 28 Jul 2020 13:48:36 +0300 Subject: [PATCH 1/5] VecDeque - say items are moved instead of copied on remove() --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 95ae823..df916d4 100644 --- a/README.md +++ b/README.md @@ -3116,7 +3116,7 @@ You need to: Watch some YouTube ## VecDeque -A `VecDeque` is a `Vec` that is good at popping items both off the front and the back. When you use `.pop()` on a `Vec`, it just takes off the last item on the right and nothing is copied. But if you take it off another part, all the items to the right are copied over. You can see this in the description for `.remove()`: +A `VecDeque` is a `Vec` that is good at popping items both off the front and the back. When you use `.pop()` on a `Vec`, it just takes off the last item on the right and nothing else is moved. But if you take it off another part, all the items to the right are moved over one position to the left. You can see this in the description for `.remove()`: ```text Removes and returns the element at position index within the vector, shifting all elements after it to the left. @@ -3135,7 +3135,7 @@ it will remove `9`. `8` in index 1 will move to index 0, `7` in index 2 will mov You don't have to worry about that with a `VecDeque`. It is usually a bit slower than a `Vec`, but if you have to do things on both ends then it is a better solution. -In this example we have a `Vec` of things to do. Then we make a `VecDeque` and use `.push_front()` to put them on the front, so the first item we added will be on the right. But each item we push is a `(&str, bool)`: `&str` is the description and `false` means it's not done yet. We use our `done()` function to pop an item off the back, but we don't want to delete it. Instead, we change `false` to `true` and push it on the front. +In this example we have a `Vec` of things to do. Then we make a `VecDeque` and use `.push_front()` to put them at the front, so the first item we added will be on the right. But each item we push is a `(&str, bool)`: `&str` is the description and `false` means it's not done yet. We use our `done()` function to pop an item off the back, but we don't want to delete it. Instead, we change `false` to `true` and push it at the front. It looks like this: @@ -3152,8 +3152,8 @@ fn check_remaining(input: &VecDeque<(&str, bool)>) { // Each item is a (&str, bo fn done(input: &mut VecDeque<(&str, bool)>) { let mut task_done = input.pop_back().unwrap(); // pop off the back - task_done.1 = true; // now it's done - mark as tru - input.push_front(task_done); // put it on the front now + task_done.1 = true; // now it's done - mark as true + input.push_front(task_done); // put it at the front now } fn main() { From a1f511f80fb55fe8dbfe9d802162e7806e2b5fed Mon Sep 17 00:00:00 2001 From: Arcadie Date: Tue, 28 Jul 2020 14:02:38 +0300 Subject: [PATCH 2/5] Generics - fix print with, specify variables of type U --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index df916d4..bf4c23b 100644 --- a/README.md +++ b/README.md @@ -3241,7 +3241,7 @@ fn main() { Now we will go back to type `T`, because Rust code usually uses `T`. -You will remember that some types in Rust are **Copy**, some are **Clone**, some are **Display**, some are **Debug**, and so on. With **Debug**, we can print with `{}`. So now you can see that this is a problem: +You will remember that some types in Rust are **Copy**, some are **Clone**, some are **Display**, some are **Debug**, and so on. With **Debug**, we can print with `{:?}`. So now you can see that this is a problem: ```rust fn print_number(number: T) { @@ -3317,7 +3317,7 @@ Here is your item: 55 Sometimes we need more than one type in a generic function. We have to write out each type name, and think about how we want to use it. In this example, we want two types. First we want to print a statement for type T. Printing with `{}` is nicer, so we will require Display for T. -Next is type U, and two variables have type U (U is some sort of number). We want to compare them, so we need PartialOrd. We want to print them too, so we require Display for U as well. +Next is type U, and the two variables `num_1` and `num_2` have type U (U is some sort of number). We want to compare them, so we need PartialOrd. We want to print them too, so we require Display for U as well. ```rust use std::fmt::Display; From 27def910d61b248fb6e3c76e22a080445b86eaf0 Mon Sep 17 00:00:00 2001 From: Arcadie Date: Tue, 28 Jul 2020 15:20:33 +0300 Subject: [PATCH 3/5] Mutex: fix output for code samples --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bf4c23b..9081294 100644 --- a/README.md +++ b/README.md @@ -6022,7 +6022,7 @@ fn main() { *mutex_changer = 6; } // mutex_changer goes out of scope - now it is gone - println!("{:?}", my_mutex); // Now it says 6 + println!("{:?}", my_mutex); // Now it says: Mutex { data: 6 } } ``` @@ -6038,7 +6038,7 @@ fn main() { std::mem::drop(mutex_changer); // drop mutex_changer - it is gone now // and my_mutex is unlocked - println!("{:?}", my_mutex); // Now it says 6 + println!("{:?}", my_mutex); // Now it says: Mutex { data: 6 } } ``` From 9e9bf0a265fed106e99dc15302b45218b3825b2e Mon Sep 17 00:00:00 2001 From: Arcadie Date: Tue, 28 Jul 2020 17:00:59 +0300 Subject: [PATCH 4/5] Arc: when spanwing threads in a loop, call join on handlers at the end --- README.md | 44 +++++++------------------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 9081294..9e3491d 100644 --- a/README.md +++ b/README.md @@ -7230,7 +7230,7 @@ fn main() { println!("The thread is working!") // Just testing the thread }); - handle.join().unwrap(); // Make the threads wait here until they are done + handle.join().unwrap(); // Make the thread wait here until it is done println!("Exiting the program"); } ``` @@ -7251,7 +7251,7 @@ fn main() { } ``` -Now let's make one more thread. Each thread will do the same thing. You can see that the threads are working at the same time. Sometimes it will say `Thread 1 is working!` first, but other times `Thread 1 is working!` is first. This is called **concurrency**, which means "running together". +Now let's make one more thread. Each thread will do the same thing. You can see that the threads are working at the same time. Sometimes it will say `Thread 1 is working!` first, but other times `Thread 2 is working!` is first. This is called **concurrency**, which means "running together". ```rust fn main() { @@ -7331,23 +7331,26 @@ Exiting the program So it was a success. Then we can join the two threads together in a single `for` loop, and make the code smaller. +We need to save the handles so we can call `.join()` on each one outside of the loop. If we do this inside the loop, it will wait for the first thread to finish before starting the new one. ```rust use std::sync::{Arc, Mutex}; fn main() { let my_number = Arc::new(Mutex::new(0)); + let mut handle_vec = vec![]; - for _ in 0..2 { // do this twice + for _ in 0..2 { // do this twice let my_number_clone = Arc::clone(&my_number); // Make the clone before starting the thread let handle = std::thread::spawn(move || { for _ in 0..10 { *my_number_clone.lock().unwrap() += 1; } }); - handle.join().unwrap(); // wait here + handle_vec.push(handle); // save the handle so we can call join on it } + handle_vec.into_iter().for_each(|handle| handle.join().unwrap()); // call join on all handles println!("{:?}", my_number); } ``` @@ -7367,39 +7370,6 @@ fn new_clone(input: &Arc>) -> Arc> { // Just a function so } // Now main() is easier to read - -fn main() { - let my_number = make_arc(0); - - for _ in 0..2 { - let my_number_clone = new_clone(&my_number); - let handle = spawn(move || { - for _ in 0..10 { - let mut value_inside = my_number_clone.lock().unwrap(); // Give the MutexGuard to a variable so it's clear - *value_inside += 1; // Now it is clear that the value inside is changing - } - }); - handle.join().unwrap(); - } - - println!("{:?}", my_number); -} -``` - -You can also make a vector of handles, and use `.join().unwrap()` on them. Then you can do what you want with each handle inside. Here is `main()` with the handles in a vector: - -```rust -use std::sync::{Arc, Mutex}; -use std::thread::spawn; // Now we just write spawn - -fn make_arc(number: i32) -> Arc> { // Just a function to make a Mutex in an Arc - Arc::new(Mutex::new(number)) -} - -fn new_clone(input: &Arc>) -> Arc> { // Just a function so we can write new_clone - Arc::clone(&input) -} - fn main() { let mut handle_vec = vec![]; // each handle will go in here let my_number = make_arc(0); From 192047be9424c691c34c7f8f2b7a23d1f6298eeb Mon Sep 17 00:00:00 2001 From: Arcadie Date: Tue, 28 Jul 2020 17:10:15 +0300 Subject: [PATCH 5/5] Delete whitespace, tweak phrasing --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9e3491d..7aa7618 100644 --- a/README.md +++ b/README.md @@ -7340,14 +7340,14 @@ fn main() { let my_number = Arc::new(Mutex::new(0)); let mut handle_vec = vec![]; - for _ in 0..2 { // do this twice + for _ in 0..2 { // do this twice let my_number_clone = Arc::clone(&my_number); // Make the clone before starting the thread let handle = std::thread::spawn(move || { for _ in 0..10 { *my_number_clone.lock().unwrap() += 1; } }); - handle_vec.push(handle); // save the handle so we can call join on it + handle_vec.push(handle); // save the handle so we can call join on it outside of the loop } handle_vec.into_iter().for_each(|handle| handle.join().unwrap()); // call join on all handles