mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-01-11 00:00:04 +03:00
Compare commits
No commits in common. "09c94bef2dbaf44daf81d8f618289c9425d1f90f" and "663a03a17b2d2001f4f3f35a59cd2e2aa5f2bb24" have entirely different histories.
09c94bef2d
...
663a03a17b
|
@ -3,35 +3,31 @@
|
||||||
// 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::{
|
use std::thread;
|
||||||
thread,
|
use std::time::{Duration, Instant};
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut handles = Vec::new();
|
let mut handles = vec![];
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
let handle = thread::spawn(move || {
|
handles.push(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 {i} done");
|
println!("thread {} is complete", i);
|
||||||
start.elapsed().as_millis()
|
start.elapsed().as_millis()
|
||||||
});
|
}));
|
||||||
handles.push(handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results: Vec<u128> = vec![];
|
||||||
for handle in handles {
|
for handle in handles {
|
||||||
// TODO: Collect the results of all threads into the `results` vector.
|
// TODO: a struct is returned from thread::spawn, can you use it?
|
||||||
// Use the `JoinHandle` struct which is returned by `thread::spawn`.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if results.len() != 10 {
|
if results.len() != 10 {
|
||||||
panic!("Oh no! Some thread isn't done yet!");
|
panic!("Oh no! All the spawned threads did not finish!");
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
for (i, result) in results.into_iter().enumerate() {
|
for (i, result) in results.into_iter().enumerate() {
|
||||||
println!("Thread {i} took {result}ms");
|
println!("thread {} took {}ms", i, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,35 @@
|
||||||
// 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_done`
|
// shared value: JobStatus.jobs_completed
|
||||||
|
|
||||||
use std::{sync::Arc, thread, time::Duration};
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
struct JobStatus {
|
struct JobStatus {
|
||||||
jobs_done: u32,
|
jobs_completed: 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_done: 0 });
|
let status = Arc::new(JobStatus { jobs_completed: 0 });
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
let mut handles = vec![];
|
||||||
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
|
||||||
// TODO: You must take an action before you update a shared value.
|
status_shared.jobs_completed += 1;
|
||||||
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_done`.
|
// TODO: Print the value of `JobStatus.jobs_completed`
|
||||||
println!("Jobs done: {}", todo!());
|
println!("Jobs completed: {}", ???);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use std::{sync::mpsc, thread, time::Duration};
|
use std::sync::mpsc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
struct Queue {
|
struct Queue {
|
||||||
length: u32,
|
length: u32,
|
||||||
|
@ -8,7 +11,7 @@ struct Queue {
|
||||||
|
|
||||||
impl Queue {
|
impl Queue {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Queue {
|
||||||
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],
|
||||||
|
@ -16,22 +19,20 @@ 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_millis(250));
|
thread::sleep(Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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_millis(250));
|
thread::sleep(Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -54,11 +55,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!("Number of received values: {total_received}");
|
println!("total numbers received: {}", total_received);
|
||||||
assert_eq!(total_received, queue_length);
|
assert_eq!(total_received, queue_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,5 @@ macro_rules! my_macro {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// TODO: Fix the macro call.
|
|
||||||
my_macro();
|
my_macro();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ 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 @@
|
||||||
// TODO: Fix the compiler error without taking the macro definition out of this
|
// Make me compile, without taking the macro out of the module!
|
||||||
// module.
|
|
||||||
mod macros {
|
mod macros {
|
||||||
macro_rules! my_macro {
|
macro_rules! my_macro {
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// TODO: Fix the compiler error by adding one or two characters.
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
macro_rules! my_macro {
|
macro_rules! my_macro {
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
// 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::consts::PI;
|
use std::f32;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Use the more accurate `PI` constant.
|
let pi = 3.14f32;
|
||||||
let pi = PI;
|
let radius = 5.00f32;
|
||||||
let radius: f32 = 5.0;
|
|
||||||
|
|
||||||
let area = pi * radius.powi(2);
|
let area = pi * f32::powi(radius, 2);
|
||||||
|
|
||||||
println!("The area of a circle with radius {radius:.2} is {area:.5}");
|
println!(
|
||||||
|
"The area of a circle with radius {:.2} is {:.5}!",
|
||||||
|
radius, area
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
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,27 +1,25 @@
|
||||||
// Here are some more easy Clippy fixes so you can see its utility 📎
|
// Here's a couple 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() {
|
||||||
println!("{:?}", my_option.unwrap());
|
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_a}; value b: {value_b}");
|
println!("value a: {}; value b: {}", value_a, 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 done.
|
finish before the spawned threads are completed.
|
||||||
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_done` so
|
to **immutable** data. But we want to *change* the number of `jobs_completed`
|
||||||
we'll need to also use another type that will only allow one thread to mutate
|
so we'll need to also use another type that will only allow one thread to
|
||||||
the data at a time. Take a look at this section of the book:
|
mutate 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_done: 0 }));
|
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 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,11 +1076,10 @@ 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.
|
||||||
|
|
||||||
Related section in The Book:
|
See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info."""
|
||||||
https://doc.rust-lang.org/book/ch16-02-message-passing.html"""
|
|
||||||
|
|
||||||
# MACROS
|
# MACROS
|
||||||
|
|
||||||
|
@ -1089,8 +1088,9 @@ 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 regular
|
When you call a macro, you need to add something special compared to a
|
||||||
function call."""
|
regular function call. If you're stuck, take a look at what's inside
|
||||||
|
`my_macro`."""
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
name = "macros2"
|
name = "macros2"
|
||||||
|
@ -1109,7 +1109,10 @@ 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"
|
||||||
|
@ -1134,7 +1137,7 @@ dir = "22_clippy"
|
||||||
test = false
|
test = false
|
||||||
strict_clippy = true
|
strict_clippy = true
|
||||||
hint = """
|
hint = """
|
||||||
Rust stores the highest precision version of some long or infinite precision
|
Rust stores the highest precision version of any 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
|
||||||
|
|
||||||
|
@ -1142,7 +1145,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 the compile output and use the
|
See the suggestions of the clippy warning in compile output and use the
|
||||||
appropriate replacement constant from `std::f32::consts`..."""
|
appropriate replacement constant from `std::f32::consts`..."""
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
|
@ -1151,8 +1154,7 @@ 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,37 +1 @@
|
||||||
// This program spawns multiple threads that each run for at least 250ms, and
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
// 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,41 +1 @@
|
||||||
// Building on the last exercise, we want all of the threads to complete their
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
// 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,66 +1 @@
|
||||||
use std::{sync::mpsc, thread, time::Duration};
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
|
|
||||||
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,10 +1 @@
|
||||||
macro_rules! my_macro {
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
() => {
|
|
||||||
println!("Check out my macro!");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
my_macro!();
|
|
||||||
// ^
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1 @@
|
||||||
// Moved the macro definition to be before its call.
|
// 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,13 +1 @@
|
||||||
// Added the attribute `macro_use` attribute.
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
#[macro_use]
|
|
||||||
mod macros {
|
|
||||||
macro_rules! my_macro {
|
|
||||||
() => {
|
|
||||||
println!("Check out my macro!");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
my_macro!();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1 @@
|
||||||
// Added semicolons to separate the macro arms.
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
#[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,17 +1 @@
|
||||||
// The Clippy tool is a collection of lints to analyze your code so you can
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
// 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,10 +1 @@
|
||||||
fn main() {
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
let mut res = 42;
|
|
||||||
let option = Some(12);
|
|
||||||
// Use `if-let` instead of iteration.
|
|
||||||
if let Some(x) = option {
|
|
||||||
res += x;
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{res}");
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,31 +1 @@
|
||||||
use std::mem;
|
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
||||||
|
|
||||||
#[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