mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-01-11 00:00:04 +03:00
Compare commits
10 commits
663a03a17b
...
09c94bef2d
Author | SHA1 | Date | |
---|---|---|---|
09c94bef2d | |||
a0e810b471 | |||
78728d5238 | |||
cc2c0958c9 | |||
4cb15a4cda | |||
9845e046de | |||
cf90364fd7 | |||
a13e3cd07f | |||
dfa2b44f71 | |||
b000164eed |
|
@ -3,31 +3,35 @@
|
||||||
// wait until all the spawned threads have finished and should collect their
|
// wait until all the spawned threads have finished and should collect their
|
||||||
// return values into a vector.
|
// return values into a vector.
|
||||||
|
|
||||||
use std::thread;
|
use std::{
|
||||||
use std::time::{Duration, Instant};
|
thread,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut handles = vec![];
|
let mut handles = Vec::new();
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
handles.push(thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
thread::sleep(Duration::from_millis(250));
|
thread::sleep(Duration::from_millis(250));
|
||||||
println!("thread {} is complete", i);
|
println!("Thread {i} done");
|
||||||
start.elapsed().as_millis()
|
start.elapsed().as_millis()
|
||||||
}));
|
});
|
||||||
|
handles.push(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut results: Vec<u128> = vec![];
|
let mut results = Vec::new();
|
||||||
for handle in handles {
|
for handle in handles {
|
||||||
// TODO: a struct is returned from thread::spawn, can you use it?
|
// TODO: Collect the results of all threads into the `results` vector.
|
||||||
|
// Use the `JoinHandle` struct which is returned by `thread::spawn`.
|
||||||
}
|
}
|
||||||
|
|
||||||
if results.len() != 10 {
|
if results.len() != 10 {
|
||||||
panic!("Oh no! All the spawned threads did not finish!");
|
panic!("Oh no! Some thread isn't done yet!");
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
for (i, result) in results.into_iter().enumerate() {
|
for (i, result) in results.into_iter().enumerate() {
|
||||||
println!("thread {} took {}ms", i, result);
|
println!("Thread {i} took {result}ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,34 @@
|
||||||
// Building on the last exercise, we want all of the threads to complete their
|
// Building on the last exercise, we want all of the threads to complete their
|
||||||
// work but this time the spawned threads need to be in charge of updating a
|
// work. But this time, the spawned threads need to be in charge of updating a
|
||||||
// shared value: JobStatus.jobs_completed
|
// shared value: `JobStatus.jobs_done`
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{sync::Arc, thread, time::Duration};
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
struct JobStatus {
|
struct JobStatus {
|
||||||
jobs_completed: u32,
|
jobs_done: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// TODO: `Arc` isn't enough if you want a **mutable** shared state
|
// TODO: `Arc` isn't enough if you want a **mutable** shared state.
|
||||||
let status = Arc::new(JobStatus { jobs_completed: 0 });
|
let status = Arc::new(JobStatus { jobs_done: 0 });
|
||||||
|
|
||||||
let mut handles = vec![];
|
let mut handles = Vec::new();
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
let status_shared = Arc::clone(&status);
|
let status_shared = Arc::clone(&status);
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
thread::sleep(Duration::from_millis(250));
|
thread::sleep(Duration::from_millis(250));
|
||||||
// TODO: You must take an action before you update a shared value
|
|
||||||
status_shared.jobs_completed += 1;
|
// TODO: You must take an action before you update a shared value.
|
||||||
|
status_shared.jobs_done += 1;
|
||||||
});
|
});
|
||||||
handles.push(handle);
|
handles.push(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Waiting for all jobs to complete
|
// Waiting for all jobs to complete.
|
||||||
for handle in handles {
|
for handle in handles {
|
||||||
handle.join().unwrap();
|
handle.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Print the value of `JobStatus.jobs_completed`
|
// TODO: Print the value of `JobStatus.jobs_done`.
|
||||||
println!("Jobs completed: {}", ???);
|
println!("Jobs done: {}", todo!());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use std::sync::mpsc;
|
use std::{sync::mpsc, thread, time::Duration};
|
||||||
use std::sync::Arc;
|
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
struct Queue {
|
struct Queue {
|
||||||
length: u32,
|
length: u32,
|
||||||
|
@ -11,7 +8,7 @@ struct Queue {
|
||||||
|
|
||||||
impl Queue {
|
impl Queue {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Queue {
|
Self {
|
||||||
length: 10,
|
length: 10,
|
||||||
first_half: vec![1, 2, 3, 4, 5],
|
first_half: vec![1, 2, 3, 4, 5],
|
||||||
second_half: vec![6, 7, 8, 9, 10],
|
second_half: vec![6, 7, 8, 9, 10],
|
||||||
|
@ -19,20 +16,22 @@ impl Queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_tx(q: Queue, tx: mpsc::Sender<u32>) -> () {
|
fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
|
||||||
|
// TODO: We want to send `tx` to both threads. But currently, it is moved
|
||||||
|
// into the frist thread. How could you solve this problem?
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
for val in q.first_half {
|
for val in q.first_half {
|
||||||
println!("sending {:?}", val);
|
println!("Sending {val:?}");
|
||||||
tx.send(val).unwrap();
|
tx.send(val).unwrap();
|
||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_millis(250));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
for val in q.second_half {
|
for val in q.second_half {
|
||||||
println!("sending {:?}", val);
|
println!("Sending {val:?}");
|
||||||
tx.send(val).unwrap();
|
tx.send(val).unwrap();
|
||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_millis(250));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -55,11 +54,11 @@ mod tests {
|
||||||
|
|
||||||
let mut total_received: u32 = 0;
|
let mut total_received: u32 = 0;
|
||||||
for received in rx {
|
for received in rx {
|
||||||
println!("Got: {}", received);
|
println!("Got: {received}");
|
||||||
total_received += 1;
|
total_received += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("total numbers received: {}", total_received);
|
println!("Number of received values: {total_received}");
|
||||||
assert_eq!(total_received, queue_length);
|
assert_eq!(total_received, queue_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,5 +5,6 @@ macro_rules! my_macro {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// TODO: Fix the macro call.
|
||||||
my_macro();
|
my_macro();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ fn main() {
|
||||||
my_macro!();
|
my_macro!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Fix the compiler error by moving the whole definition of this macro.
|
||||||
macro_rules! my_macro {
|
macro_rules! my_macro {
|
||||||
() => {
|
() => {
|
||||||
println!("Check out my macro!");
|
println!("Check out my macro!");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Make me compile, without taking the macro out of the module!
|
// TODO: Fix the compiler error without taking the macro definition out of this
|
||||||
|
// module.
|
||||||
mod macros {
|
mod macros {
|
||||||
macro_rules! my_macro {
|
macro_rules! my_macro {
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// TODO: Fix the compiler error by adding one or two characters.
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
macro_rules! my_macro {
|
macro_rules! my_macro {
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
// The Clippy tool is a collection of lints to analyze your code so you can
|
// The Clippy tool is a collection of lints to analyze your code so you can
|
||||||
// catch common mistakes and improve your Rust code.
|
// catch common mistakes and improve your Rust code.
|
||||||
//
|
//
|
||||||
// For these exercises the code will fail to compile when there are Clippy
|
// For these exercises, the code will fail to compile when there are Clippy
|
||||||
// warnings. Check Clippy's suggestions from the output to solve the exercise.
|
// warnings. Check Clippy's suggestions from the output to solve the exercise.
|
||||||
|
|
||||||
use std::f32;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let pi = 3.14f32;
|
// Use the more accurate `PI` constant.
|
||||||
let radius = 5.00f32;
|
let pi = PI;
|
||||||
|
let radius: f32 = 5.0;
|
||||||
|
|
||||||
let area = pi * f32::powi(radius, 2);
|
let area = pi * radius.powi(2);
|
||||||
|
|
||||||
println!(
|
println!("The area of a circle with radius {radius:.2} is {area:.5}");
|
||||||
"The area of a circle with radius {:.2} is {:.5}!",
|
|
||||||
radius, area
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut res = 42;
|
let mut res = 42;
|
||||||
let option = Some(12);
|
let option = Some(12);
|
||||||
|
// TODO: Fix the Clippy lint.
|
||||||
for x in option {
|
for x in option {
|
||||||
res += x;
|
res += x;
|
||||||
}
|
}
|
||||||
println!("{}", res);
|
|
||||||
|
println!("{res}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
// Here's a couple more easy Clippy fixes, so you can see its utility.
|
// Here are some more easy Clippy fixes so you can see its utility 📎
|
||||||
|
// TODO: Fix all the Clippy lints.
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
#[allow(unused_variables, unused_assignments)]
|
#[allow(unused_variables, unused_assignments)]
|
||||||
fn main() {
|
fn main() {
|
||||||
let my_option: Option<()> = None;
|
let my_option: Option<()> = None;
|
||||||
if my_option.is_none() {
|
if my_option.is_none() {
|
||||||
my_option.unwrap();
|
println!("{:?}", my_option.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let my_arr = &[
|
let my_arr = &[
|
||||||
-1, -2, -3
|
-1, -2, -3
|
||||||
-4, -5, -6
|
-4, -5, -6
|
||||||
];
|
];
|
||||||
println!("My array! Here it is: {:?}", my_arr);
|
println!("My array! Here it is: {my_arr:?}");
|
||||||
|
|
||||||
let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
|
let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
|
||||||
println!("This Vec is empty, see? {:?}", my_empty_vec);
|
println!("This Vec is empty, see? {my_empty_vec:?}");
|
||||||
|
|
||||||
let mut value_a = 45;
|
let mut value_a = 45;
|
||||||
let mut value_b = 66;
|
let mut value_b = 66;
|
||||||
// Let's swap these two!
|
// Let's swap these two!
|
||||||
value_a = value_b;
|
value_a = value_b;
|
||||||
value_b = value_a;
|
value_b = value_a;
|
||||||
println!("value a: {}; value b: {}", value_a, value_b);
|
println!("value a: {value_a}; value b: {value_b}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1037,7 +1037,7 @@ hint = """
|
||||||
https://doc.rust-lang.org/std/thread/fn.spawn.html
|
https://doc.rust-lang.org/std/thread/fn.spawn.html
|
||||||
|
|
||||||
A challenge with multi-threaded applications is that the main thread can
|
A challenge with multi-threaded applications is that the main thread can
|
||||||
finish before the spawned threads are completed.
|
finish before the spawned threads are done.
|
||||||
https://doc.rust-lang.org/book/ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handles
|
https://doc.rust-lang.org/book/ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handles
|
||||||
|
|
||||||
Use the `JoinHandle`s to wait for each thread to finish and collect their
|
Use the `JoinHandle`s to wait for each thread to finish and collect their
|
||||||
|
@ -1051,19 +1051,19 @@ dir = "20_threads"
|
||||||
test = false
|
test = false
|
||||||
hint = """
|
hint = """
|
||||||
`Arc` is an Atomic Reference Counted pointer that allows safe, shared access
|
`Arc` is an Atomic Reference Counted pointer that allows safe, shared access
|
||||||
to **immutable** data. But we want to *change* the number of `jobs_completed`
|
to **immutable** data. But we want to *change* the number of `jobs_done` so
|
||||||
so we'll need to also use another type that will only allow one thread to
|
we'll need to also use another type that will only allow one thread to mutate
|
||||||
mutate the data at a time. Take a look at this section of the book:
|
the data at a time. Take a look at this section of the book:
|
||||||
https://doc.rust-lang.org/book/ch16-03-shared-state.html#atomic-reference-counting-with-arct
|
https://doc.rust-lang.org/book/ch16-03-shared-state.html#atomic-reference-counting-with-arct
|
||||||
|
|
||||||
Keep reading if you'd like more hints :)
|
Keep reading if you'd like more hints :)
|
||||||
|
|
||||||
Do you now have an `Arc<Mutex<JobStatus>>` at the beginning of `main`? Like:
|
Do you now have an `Arc<Mutex<JobStatus>>` at the beginning of `main`? Like:
|
||||||
```
|
```
|
||||||
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
|
let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
|
||||||
```
|
```
|
||||||
|
|
||||||
Similar to the code in the following example in the book:
|
Similar to the code in the following example in The Book:
|
||||||
https://doc.rust-lang.org/book/ch16-03-shared-state.html#sharing-a-mutext-between-multiple-threads"""
|
https://doc.rust-lang.org/book/ch16-03-shared-state.html#sharing-a-mutext-between-multiple-threads"""
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
|
@ -1076,10 +1076,11 @@ An alternate way to handle concurrency between threads is to use an `mpsc`
|
||||||
With both a sending end and a receiving end, it's possible to send values in
|
With both a sending end and a receiving end, it's possible to send values in
|
||||||
one thread and receive them in another.
|
one thread and receive them in another.
|
||||||
|
|
||||||
Multiple producers are possible by using clone() to create a duplicate of the
|
Multiple producers are possible by using `clone()` to create a duplicate of the
|
||||||
original sending end.
|
original sending end.
|
||||||
|
|
||||||
See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info."""
|
Related section in The Book:
|
||||||
|
https://doc.rust-lang.org/book/ch16-02-message-passing.html"""
|
||||||
|
|
||||||
# MACROS
|
# MACROS
|
||||||
|
|
||||||
|
@ -1088,9 +1089,8 @@ name = "macros1"
|
||||||
dir = "21_macros"
|
dir = "21_macros"
|
||||||
test = false
|
test = false
|
||||||
hint = """
|
hint = """
|
||||||
When you call a macro, you need to add something special compared to a
|
When you call a macro, you need to add something special compared to a regular
|
||||||
regular function call. If you're stuck, take a look at what's inside
|
function call."""
|
||||||
`my_macro`."""
|
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
name = "macros2"
|
name = "macros2"
|
||||||
|
@ -1109,10 +1109,7 @@ dir = "21_macros"
|
||||||
test = false
|
test = false
|
||||||
hint = """
|
hint = """
|
||||||
In order to use a macro outside of its module, you need to do something
|
In order to use a macro outside of its module, you need to do something
|
||||||
special to the module to lift the macro out into its parent.
|
special to the module to lift the macro out into its parent."""
|
||||||
|
|
||||||
The same trick also works on "extern crate" statements for crates that have
|
|
||||||
exported macros, if you've seen any of those around."""
|
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
name = "macros4"
|
name = "macros4"
|
||||||
|
@ -1137,7 +1134,7 @@ dir = "22_clippy"
|
||||||
test = false
|
test = false
|
||||||
strict_clippy = true
|
strict_clippy = true
|
||||||
hint = """
|
hint = """
|
||||||
Rust stores the highest precision version of any long or infinite precision
|
Rust stores the highest precision version of some long or infinite precision
|
||||||
mathematical constants in the Rust standard library:
|
mathematical constants in the Rust standard library:
|
||||||
https://doc.rust-lang.org/stable/std/f32/consts/index.html
|
https://doc.rust-lang.org/stable/std/f32/consts/index.html
|
||||||
|
|
||||||
|
@ -1145,7 +1142,7 @@ We may be tempted to use our own approximations for certain mathematical
|
||||||
constants, but clippy recognizes those imprecise mathematical constants as a
|
constants, but clippy recognizes those imprecise mathematical constants as a
|
||||||
source of potential error.
|
source of potential error.
|
||||||
|
|
||||||
See the suggestions of the clippy warning in compile output and use the
|
See the suggestions of the Clippy warning in the compile output and use the
|
||||||
appropriate replacement constant from `std::f32::consts`..."""
|
appropriate replacement constant from `std::f32::consts`..."""
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
|
@ -1154,7 +1151,8 @@ dir = "22_clippy"
|
||||||
test = false
|
test = false
|
||||||
strict_clippy = true
|
strict_clippy = true
|
||||||
hint = """
|
hint = """
|
||||||
`for` loops over `Option` values are more clearly expressed as an `if let`"""
|
`for` loops over `Option` values are more clearly expressed as an `if-let`
|
||||||
|
statement."""
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
name = "clippy3"
|
name = "clippy3"
|
||||||
|
|
|
@ -1 +1,37 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
// This program spawns multiple threads that each run for at least 250ms, and
|
||||||
|
// each thread returns how much time they took to complete. The program should
|
||||||
|
// wait until all the spawned threads have finished and should collect their
|
||||||
|
// return values into a vector.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
thread,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut handles = Vec::new();
|
||||||
|
for i in 0..10 {
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
let start = Instant::now();
|
||||||
|
thread::sleep(Duration::from_millis(250));
|
||||||
|
println!("Thread {i} done");
|
||||||
|
start.elapsed().as_millis()
|
||||||
|
});
|
||||||
|
handles.push(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut results = Vec::new();
|
||||||
|
for handle in handles {
|
||||||
|
// Collect the results of all threads into the `results` vector.
|
||||||
|
results.push(handle.join().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if results.len() != 10 {
|
||||||
|
panic!("Oh no! Some thread isn't done yet!");
|
||||||
|
}
|
||||||
|
|
||||||
|
println!();
|
||||||
|
for (i, result) in results.into_iter().enumerate() {
|
||||||
|
println!("Thread {i} took {result}ms");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,41 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
// Building on the last exercise, we want all of the threads to complete their
|
||||||
|
// work. But this time, the spawned threads need to be in charge of updating a
|
||||||
|
// shared value: `JobStatus.jobs_done`
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JobStatus {
|
||||||
|
jobs_done: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// `Arc` isn't enough if you want a **mutable** shared state.
|
||||||
|
// We need to wrap the value with a `Mutex`.
|
||||||
|
let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
|
||||||
|
// ^^^^^^^^^^^ ^
|
||||||
|
|
||||||
|
let mut handles = Vec::new();
|
||||||
|
for _ in 0..10 {
|
||||||
|
let status_shared = Arc::clone(&status);
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
thread::sleep(Duration::from_millis(250));
|
||||||
|
|
||||||
|
// Lock before you update a shared value.
|
||||||
|
status_shared.lock().unwrap().jobs_done += 1;
|
||||||
|
// ^^^^^^^^^^^^^^^^
|
||||||
|
});
|
||||||
|
handles.push(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Waiting for all jobs to complete.
|
||||||
|
for handle in handles {
|
||||||
|
handle.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Jobs done: {}", status.lock().unwrap().jobs_done);
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,66 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
use std::{sync::mpsc, thread, time::Duration};
|
||||||
|
|
||||||
|
struct Queue {
|
||||||
|
length: u32,
|
||||||
|
first_half: Vec<u32>,
|
||||||
|
second_half: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Queue {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
length: 10,
|
||||||
|
first_half: vec![1, 2, 3, 4, 5],
|
||||||
|
second_half: vec![6, 7, 8, 9, 10],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
|
||||||
|
// Clone the sender `tx` first.
|
||||||
|
let tx_clone = tx.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
for val in q.first_half {
|
||||||
|
println!("Sending {val:?}");
|
||||||
|
// Then use the clone in the first thread. This means that
|
||||||
|
// `tx_clone` is moved to the first thread and `tx` to the second.
|
||||||
|
tx_clone.send(val).unwrap();
|
||||||
|
thread::sleep(Duration::from_millis(250));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
for val in q.second_half {
|
||||||
|
println!("Sending {val:?}");
|
||||||
|
tx.send(val).unwrap();
|
||||||
|
thread::sleep(Duration::from_millis(250));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// You can optionally experiment here.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn threads3() {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
let queue = Queue::new();
|
||||||
|
let queue_length = queue.length;
|
||||||
|
|
||||||
|
send_tx(queue, tx);
|
||||||
|
|
||||||
|
let mut total_received: u32 = 0;
|
||||||
|
for received in rx {
|
||||||
|
println!("Got: {received}");
|
||||||
|
total_received += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Number of received values: {total_received}");
|
||||||
|
assert_eq!(total_received, queue_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,10 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
macro_rules! my_macro {
|
||||||
|
() => {
|
||||||
|
println!("Check out my macro!");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
my_macro!();
|
||||||
|
// ^
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,10 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
// Moved the macro definition to be before its call.
|
||||||
|
macro_rules! my_macro {
|
||||||
|
() => {
|
||||||
|
println!("Check out my macro!");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
my_macro!();
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,13 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
// Added the attribute `macro_use` attribute.
|
||||||
|
#[macro_use]
|
||||||
|
mod macros {
|
||||||
|
macro_rules! my_macro {
|
||||||
|
() => {
|
||||||
|
println!("Check out my macro!");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
my_macro!();
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,15 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
// Added semicolons to separate the macro arms.
|
||||||
|
#[rustfmt::skip]
|
||||||
|
macro_rules! my_macro {
|
||||||
|
() => {
|
||||||
|
println!("Check out my macro!");
|
||||||
|
};
|
||||||
|
($val:expr) => {
|
||||||
|
println!("Look at this other macro: {}", $val);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
my_macro!();
|
||||||
|
my_macro!(7777);
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,17 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
// The Clippy tool is a collection of lints to analyze your code so you can
|
||||||
|
// catch common mistakes and improve your Rust code.
|
||||||
|
//
|
||||||
|
// For these exercises, the code will fail to compile when there are Clippy
|
||||||
|
// warnings. Check Clippy's suggestions from the output to solve the exercise.
|
||||||
|
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Use the more accurate `PI` constant.
|
||||||
|
let pi = PI;
|
||||||
|
let radius: f32 = 5.0;
|
||||||
|
|
||||||
|
let area = pi * radius.powi(2);
|
||||||
|
|
||||||
|
println!("The area of a circle with radius {radius:.2} is {area:.5}");
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,10 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
fn main() {
|
||||||
|
let mut res = 42;
|
||||||
|
let option = Some(12);
|
||||||
|
// Use `if-let` instead of iteration.
|
||||||
|
if let Some(x) = option {
|
||||||
|
res += x;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{res}");
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,31 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
use std::mem;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(unused_variables, unused_assignments)]
|
||||||
|
fn main() {
|
||||||
|
let my_option: Option<()> = None;
|
||||||
|
// `unwrap` of an `Option` after checking if it is `None` will panic.
|
||||||
|
// Use `if-let` instead.
|
||||||
|
if let Some(value) = my_option {
|
||||||
|
println!("{value:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A comma was missing.
|
||||||
|
let my_arr = &[
|
||||||
|
-1, -2, -3,
|
||||||
|
-4, -5, -6,
|
||||||
|
];
|
||||||
|
println!("My array! Here it is: {:?}", my_arr);
|
||||||
|
|
||||||
|
let mut my_empty_vec = vec![1, 2, 3, 4, 5];
|
||||||
|
// `resize` mutates a vector instead of returning a new one.
|
||||||
|
// `resize(0, …)` clears a vector, so it is better to use `clear`.
|
||||||
|
my_empty_vec.clear();
|
||||||
|
println!("This Vec is empty, see? {my_empty_vec:?}");
|
||||||
|
|
||||||
|
let mut value_a = 45;
|
||||||
|
let mut value_b = 66;
|
||||||
|
// Use `mem::swap` to correctly swap two values.
|
||||||
|
mem::swap(&mut value_a, &mut value_b);
|
||||||
|
println!("value a: {}; value b: {}", value_a, value_b);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue