diff options
Diffstat (limited to 'exercises')
27 files changed, 145 insertions, 92 deletions
diff --git a/exercises/README.md b/exercises/README.md index e52137c..c7effa9 100644 --- a/exercises/README.md +++ b/exercises/README.md @@ -7,7 +7,7 @@ | if | §3.5 | | primitive_types | §3.2, §4.3 | | vecs | §8.1 | -| move_semantics | §4.1, §4.2 | +| move_semantics | §4.1-2 | | structs | §5.1, §5.3 | | enums | §6, §18.3 | | strings | §8.2 | @@ -19,8 +19,9 @@ | traits | §10.2 | | tests | §11.1 | | lifetimes | §10.3 | -| standard_library_types | §13.2, §15.1, §16.3 | -| threads | §16.1, §16.2, §16.3 | +| iterators | §13.2-4 | +| threads | §16.1-3 | +| smart_pointers | §15, §16.3 | | macros | §19.6 | -| clippy | n/a | +| clippy | §21.4 | | conversions | n/a | diff --git a/exercises/conversions/as_ref_mut.rs b/exercises/conversions/as_ref_mut.rs index c9eed7d..e6a9d11 100644 --- a/exercises/conversions/as_ref_mut.rs +++ b/exercises/conversions/as_ref_mut.rs @@ -5,21 +5,22 @@ // I AM NOT DONE -// Obtain the number of bytes (not characters) in the given argument -// Add the AsRef trait appropriately as a trait bound +// Obtain the number of bytes (not characters) in the given argument. +// TODO: Add the AsRef trait appropriately as a trait bound. fn byte_counter<T>(arg: T) -> usize { arg.as_ref().as_bytes().len() } -// Obtain the number of characters (not bytes) in the given argument -// Add the AsRef trait appropriately as a trait bound +// Obtain the number of characters (not bytes) in the given argument. +// TODO: Add the AsRef trait appropriately as a trait bound. fn char_counter<T>(arg: T) -> usize { arg.as_ref().chars().count() } -// Squares a number using as_mut(). Add the trait bound as is appropriate and -// implement the function body. +// Squares a number using as_mut(). +// TODO: Add the appropriate trait bound. fn num_sq<T>(arg: &mut T) { + // TODO: Implement the function body. ??? } diff --git a/exercises/enums/enums2.rs b/exercises/enums/enums2.rs index 18479f8..167a6b2 100644 --- a/exercises/enums/enums2.rs +++ b/exercises/enums/enums2.rs @@ -10,7 +10,7 @@ enum Message { impl Message { fn call(&self) { - println!("{:?}", &self); + println!("{:?}", self); } } diff --git a/exercises/enums/enums3.rs b/exercises/enums/enums3.rs index 55acf6b..a2a9d58 100644 --- a/exercises/enums/enums3.rs +++ b/exercises/enums/enums3.rs @@ -38,6 +38,7 @@ impl State { fn process(&mut self, message: Message) { // TODO: create a match expression to process the different message variants + // Remember: When passing a tuple as a function argument, you'll need extra parentheses: fn function((t, u, p, l, e)) } } @@ -52,7 +53,7 @@ mod tests { position: Point { x: 0, y: 0 }, color: (0, 0, 0), }; - state.process(Message::ChangeColor((255, 0, 255))); + state.process(Message::ChangeColor(255, 0, 255)); state.process(Message::Echo(String::from("hello world"))); state.process(Message::Move(Point { x: 10, y: 15 })); state.process(Message::Quit); diff --git a/exercises/error_handling/errors5.rs b/exercises/error_handling/errors5.rs index 6da06ef..eb5506c 100644 --- a/exercises/error_handling/errors5.rs +++ b/exercises/error_handling/errors5.rs @@ -4,7 +4,7 @@ // This exercise uses some concepts that we won't get to until later in the course, like `Box` and the // `From` trait. It's not important to understand them in detail right now, but you can read ahead if you like. -// For now, think of the `Box<dyn ...>` type as an "I want anything that does ???" type, which, given +// For now, think of the `Box<dyn ???>` type as an "I want anything that does ???" type, which, given // Rust's usual standards for runtime safety, should strike you as somewhat lenient! // In short, this particular use case for boxes is for when you want to own a value and you care only that it is a diff --git a/exercises/hashmaps/hashmaps3.rs b/exercises/hashmaps/hashmaps3.rs index 18dd44c..ad3baa6 100644 --- a/exercises/hashmaps/hashmaps3.rs +++ b/exercises/hashmaps/hashmaps3.rs @@ -37,7 +37,7 @@ fn build_scores_table(results: String) -> HashMap<String, Team> { let team_2_score: u8 = v[3].parse().unwrap(); // TODO: Populate the scores table with details extracted from the // current line. Keep in mind that goals scored by team_1 - // will be number of goals conceded from team_2, and similarly + // will be the number of goals conceded from team_2, and similarly // goals scored by team_2 will be the number of goals conceded by // team_1. } diff --git a/exercises/intro/intro1.rs b/exercises/intro/intro1.rs index 45c5acb..cfc55c3 100644 --- a/exercises/intro/intro1.rs +++ b/exercises/intro/intro1.rs @@ -26,5 +26,12 @@ fn main() { println!("solve the exercises. Good luck!"); println!(); println!("The source for this exercise is in `exercises/intro/intro1.rs`. Have a look!"); - println!("Going forward, the source of the exercises will always be in the success/failure output."); + println!( + "Going forward, the source of the exercises will always be in the success/failure output." + ); + println!(); + println!( + "If you want to use rust-analyzer, Rust's LSP implementation, make sure your editor is set" + ); + println!("up, and then run `rustlings lsp` before continuing.") } diff --git a/exercises/iterators/README.md b/exercises/iterators/README.md new file mode 100644 index 0000000..0e8b671 --- /dev/null +++ b/exercises/iterators/README.md @@ -0,0 +1,8 @@ +# Iterators + +This section will teach you about Iterators. + +## Further information + +- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) +- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/) diff --git a/exercises/standard_library_types/iterators1.rs b/exercises/iterators/iterators1.rs index 0379c6b..0379c6b 100644 --- a/exercises/standard_library_types/iterators1.rs +++ b/exercises/iterators/iterators1.rs diff --git a/exercises/standard_library_types/iterators2.rs b/exercises/iterators/iterators2.rs index 29c53af..29c53af 100644 --- a/exercises/standard_library_types/iterators2.rs +++ b/exercises/iterators/iterators2.rs diff --git a/exercises/standard_library_types/iterators3.rs b/exercises/iterators/iterators3.rs index c97a625..c97a625 100644 --- a/exercises/standard_library_types/iterators3.rs +++ b/exercises/iterators/iterators3.rs diff --git a/exercises/standard_library_types/iterators4.rs b/exercises/iterators/iterators4.rs index a02470e..a02470e 100644 --- a/exercises/standard_library_types/iterators4.rs +++ b/exercises/iterators/iterators4.rs diff --git a/exercises/standard_library_types/iterators5.rs b/exercises/iterators/iterators5.rs index 0593d12..0593d12 100644 --- a/exercises/standard_library_types/iterators5.rs +++ b/exercises/iterators/iterators5.rs diff --git a/exercises/options/options1.rs b/exercises/options/options1.rs index 1149af0..1f891b0 100644 --- a/exercises/options/options1.rs +++ b/exercises/options/options1.rs @@ -6,10 +6,10 @@ // This function returns how much icecream there is left in the fridge. // If it's before 10PM, there's 5 pieces left. At 10PM, someone eats them // all, so there'll be no more left :( -// TODO: Return an Option! fn maybe_icecream(time_of_day: u16) -> Option<u16> { // We use the 24-hour system here, so 10PM is a value of 22 and 12AM is a value of 0 // The Option output should gracefully handle cases where time_of_day > 23. + // TODO: Complete the function body - remember to return an Option! ??? } diff --git a/exercises/options/options2.rs b/exercises/options/options2.rs index b112047..4e36443 100644 --- a/exercises/options/options2.rs +++ b/exercises/options/options2.rs @@ -5,8 +5,6 @@ #[cfg(test)] mod tests { - use super::*; - #[test] fn simple_option() { let target = "rustlings"; diff --git a/exercises/quiz2.rs b/exercises/quiz2.rs index 606d3c7..5c42dae 100644 --- a/exercises/quiz2.rs +++ b/exercises/quiz2.rs @@ -6,7 +6,7 @@ // - Modules // - Enums -// Let's build a little machine in form of a function. +// Let's build a little machine in the form of a function. // As input, we're going to give a list of strings and commands. These commands // determine what action is going to be applied to the string. It can either be: // - Uppercase the string @@ -42,7 +42,7 @@ mod my_module { #[cfg(test)] mod tests { - // TODO: What do we have to import to have `transformer` in scope? + // TODO: What do we need to import to have `transformer` in scope? use ???; use super::Command; diff --git a/exercises/smart_pointers/README.md b/exercises/smart_pointers/README.md new file mode 100644 index 0000000..c517ae3 --- /dev/null +++ b/exercises/smart_pointers/README.md @@ -0,0 +1,11 @@ +# Smart Pointers +In Rust, smart pointers are variables that contain an address in memory and reference some other data, but they also have additional metadata and capabilities. +Smart pointers in Rust often own the data they point to, while references only borrow data. + +## Further Information + +- [Smart Pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html) +- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html) +- [Rc\<T\>, the Reference Counted Smart Pointer](https://doc.rust-lang.org/book/ch15-04-rc.html) +- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) +- [Cow Documentation](https://doc.rust-lang.org/std/borrow/enum.Cow.html) diff --git a/exercises/standard_library_types/arc1.rs b/exercises/smart_pointers/arc1.rs index 93a2703..ffb306a 100644 --- a/exercises/standard_library_types/arc1.rs +++ b/exercises/smart_pointers/arc1.rs @@ -32,7 +32,7 @@ fn main() { for offset in 0..8 { let child_numbers = // TODO joinhandles.push(thread::spawn(move || { - let sum: u32 = child_numbers.iter().filter(|n| *n % 8 == offset).sum(); + let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum(); println!("Sum of offset {} is {}", offset, sum); })); } diff --git a/exercises/standard_library_types/box1.rs b/exercises/smart_pointers/box1.rs index 66cf00f..66cf00f 100644 --- a/exercises/standard_library_types/box1.rs +++ b/exercises/smart_pointers/box1.rs diff --git a/exercises/smart_pointers/cow1.rs b/exercises/smart_pointers/cow1.rs new file mode 100644 index 0000000..885138a --- /dev/null +++ b/exercises/smart_pointers/cow1.rs @@ -0,0 +1,74 @@ +// cow1.rs + +// This exercise explores the Cow, or Clone-On-Write type. +// Cow is a clone-on-write smart pointer. +// It can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required. +// The type is designed to work with general borrowed data via the Borrow trait. +// +// This exercise is meant to show you what to expect when passing data to Cow. +// Fix the unit tests by checking for Cow::Owned(_) and Cow::Borrowed(_) at the TODO markers. + +// I AM NOT DONE + +use std::borrow::Cow; + +fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> { + for i in 0..input.len() { + let v = input[i]; + if v < 0 { + // Clones into a vector if not already owned. + input.to_mut()[i] = -v; + } + } + input +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn reference_mutation() -> Result<(), &'static str> { + // Clone occurs because `input` needs to be mutated. + let slice = [-1, 0, 1]; + let mut input = Cow::from(&slice[..]); + match abs_all(&mut input) { + Cow::Owned(_) => Ok(()), + _ => Err("Expected owned value"), + } + } + + #[test] + fn reference_no_mutation() -> Result<(), &'static str> { + // No clone occurs because `input` doesn't need to be mutated. + let slice = [0, 1, 2]; + let mut input = Cow::from(&slice[..]); + match abs_all(&mut input) { + // TODO + } + } + + #[test] + fn owned_no_mutation() -> Result<(), &'static str> { + // We can also pass `slice` without `&` so Cow owns it directly. + // In this case no mutation occurs and thus also no clone, + // but the result is still owned because it always was. + let slice = vec![0, 1, 2]; + let mut input = Cow::from(slice); + match abs_all(&mut input) { + // TODO + } + } + + #[test] + fn owned_mutation() -> Result<(), &'static str> { + // Of course this is also the case if a mutation does occur. + // In this case the call to `to_mut()` returns a reference to + // the same data as before. + let slice = vec![-1, 0, 1]; + let mut input = Cow::from(slice); + match abs_all(&mut input) { + // TODO + } + } +} diff --git a/exercises/standard_library_types/rc1.rs b/exercises/smart_pointers/rc1.rs index 9b907fd..d62f361 100644 --- a/exercises/standard_library_types/rc1.rs +++ b/exercises/smart_pointers/rc1.rs @@ -6,6 +6,7 @@ // Make this code compile by using the proper Rc primitives to express that the sun has multiple owners. // I AM NOT DONE + use std::rc::Rc; #[derive(Debug)] diff --git a/exercises/standard_library_types/README.md b/exercises/standard_library_types/README.md deleted file mode 100644 index 809d61f..0000000 --- a/exercises/standard_library_types/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Standard library types - -This section will teach you about Box, Shared-State Concurrency and Iterators. - -## Further information - -- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html) -- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) -- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) -- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/) diff --git a/exercises/standard_library_types/cow1.rs b/exercises/standard_library_types/cow1.rs deleted file mode 100644 index 5fba251..0000000 --- a/exercises/standard_library_types/cow1.rs +++ /dev/null @@ -1,48 +0,0 @@ -// cow1.rs - -// This exercise explores the Cow, or Clone-On-Write type. -// Cow is a clone-on-write smart pointer. -// It can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required. -// The type is designed to work with general borrowed data via the Borrow trait. - -// I AM NOT DONE - -use std::borrow::Cow; - -fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> { - for i in 0..input.len() { - let v = input[i]; - if v < 0 { - // Clones into a vector if not already owned. - input.to_mut()[i] = -v; - } - } - input -} - -fn main() { - // No clone occurs because `input` doesn't need to be mutated. - let slice = [0, 1, 2]; - let mut input = Cow::from(&slice[..]); - match abs_all(&mut input) { - Cow::Borrowed(_) => println!("I borrowed the slice!"), - _ => panic!("expected borrowed value"), - } - - // Clone occurs because `input` needs to be mutated. - let slice = [-1, 0, 1]; - let mut input = Cow::from(&slice[..]); - match abs_all(&mut input) { - Cow::Owned(_) => println!("I modified the slice and now own it!"), - _ => panic!("expected owned value"), - } - - // No clone occurs because `input` is already owned. - let slice = vec![-1, 0, 1]; - let mut input = Cow::from(slice); - match abs_all(&mut input) { - // TODO - Cow::Borrowed(_) => println!("I own this slice!"), - _ => panic!("expected borrowed value"), - } -} diff --git a/exercises/threads/threads1.rs b/exercises/threads/threads1.rs index e59f4ce..d6376db 100644 --- a/exercises/threads/threads1.rs +++ b/exercises/threads/threads1.rs @@ -1,31 +1,38 @@ // threads1.rs // Execute `rustlings hint threads1` or use the `hint` watch subcommand for a hint. -// This program should wait until all the spawned threads have finished before exiting. + +// 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. // I AM NOT DONE use std::thread; -use std::time::Duration; - +use std::time::{Duration, Instant}; fn main() { - let mut handles = vec![]; for i in 0..10 { - thread::spawn(move || { + handles.push(thread::spawn(move || { + let start = Instant::now(); thread::sleep(Duration::from_millis(250)); println!("thread {} is complete", i); - }); + start.elapsed().as_millis() + })); } - let mut completed_threads = 0; + let mut results: Vec<u128> = vec![]; for handle in handles { // TODO: a struct is returned from thread::spawn, can you use it? - completed_threads += 1; } - if completed_threads != 10 { + if results.len() != 10 { panic!("Oh no! All the spawned threads did not finish!"); } + println!(); + for (i, result) in results.into_iter().enumerate() { + println!("thread {} took {}ms", i, result); + } } diff --git a/exercises/traits/traits1.rs b/exercises/traits/traits1.rs index 5b9d8d5..f5320a5 100644 --- a/exercises/traits/traits1.rs +++ b/exercises/traits/traits1.rs @@ -2,7 +2,7 @@ // Time to implement some traits! // // Your task is to implement the trait -// `AppendBar' for the type `String'. +// `AppendBar` for the type `String`. // // The trait AppendBar has only one function, // which appends "Bar" to any object @@ -16,7 +16,7 @@ trait AppendBar { } impl AppendBar for String { - //Add your code here + // TODO: Implement `AppendBar` for type `String`. } fn main() { diff --git a/exercises/traits/traits2.rs b/exercises/traits/traits2.rs index 708bb19..288b498 100644 --- a/exercises/traits/traits2.rs +++ b/exercises/traits/traits2.rs @@ -1,7 +1,7 @@ // traits2.rs // // Your task is to implement the trait -// `AppendBar' for a vector of strings. +// `AppendBar` for a vector of strings. // // To implement this trait, consider for // a moment what it means to 'append "Bar"' @@ -17,7 +17,7 @@ trait AppendBar { fn append_bar(self) -> Self; } -//TODO: Add your code here +// TODO: Implement trait `AppendBar` for a vector of strings. #[cfg(test)] mod tests { diff --git a/exercises/vecs/README.md b/exercises/vecs/README.md index ebe90bf..8ff9b85 100644 --- a/exercises/vecs/README.md +++ b/exercises/vecs/README.md @@ -13,3 +13,5 @@ the other useful data structure, hash maps, later. ## Further information - [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html) +- [`iter_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.iter_mut) +- [`map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) |
