diff --git a/exercises/enums/enums1.rs b/exercises/enums/enums1.rs index f490928c..a2223d33 100644 --- a/exercises/enums/enums1.rs +++ b/exercises/enums/enums1.rs @@ -1,5 +1,5 @@ // enums1.rs -// Make me compile! Scroll down for hints! +// Make me compile! Execute `rustlings hint enums1` for hints! // I AM NOT DONE @@ -14,31 +14,3 @@ fn main() { println!("{:?}", Message::Move); println!("{:?}", Message::ChangeColor); } - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Hint: The declaration of the enumeration type has not been defined yet. diff --git a/exercises/enums/enums2.rs b/exercises/enums/enums2.rs index 8f04bd87..52ccb221 100644 --- a/exercises/enums/enums2.rs +++ b/exercises/enums/enums2.rs @@ -1,5 +1,5 @@ // enums2.rs -// Make me compile! Scroll down for hints +// Make me compile! Execute `rustlings hint enums2` for hints! // I AM NOT DONE @@ -26,38 +26,3 @@ fn main() { message.call(); } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Hint: you can create enumerations that have different variants with different types -// such as no data, anonymous structs, a single string, tuples, ...etc diff --git a/exercises/error_handling/errors1.rs b/exercises/error_handling/errors1.rs index a06f0cae..9c24d85d 100644 --- a/exercises/error_handling/errors1.rs +++ b/exercises/error_handling/errors1.rs @@ -4,7 +4,7 @@ // was, instead of just sometimes returning `None`. The 2nd test currently // does not compile or pass, but it illustrates the behavior we would like // this function to have. -// Scroll down for hints!!! +// Execute `rustlings hint errors1` for hints! // I AM NOT DONE @@ -40,36 +40,3 @@ mod tests { ); } } - - - - - - - - - - - - - - - - - - - - -// `Err` is one of the variants of `Result`, so what the 2nd test is saying -// is that `generate_nametag_text` should return a `Result` instead of an -// `Option`. - -// To make this change, you'll need to: -// - update the return type in the function signature to be a Result that -// could be the variants `Ok(String)` and `Err(String)` -// - change the body of the function to return `Ok(stuff)` where it currently -// returns `Some(stuff)` -// - change the body of the function to return `Err(error message)` where it -// currently returns `None` -// - change the first test to expect `Ok(stuff)` where it currently expects -// `Some(stuff)`. diff --git a/exercises/error_handling/errors2.rs b/exercises/error_handling/errors2.rs index 315528f4..aad3a93f 100644 --- a/exercises/error_handling/errors2.rs +++ b/exercises/error_handling/errors2.rs @@ -14,7 +14,7 @@ // and add. // There are at least two ways to implement this that are both correct-- but -// one is a lot shorter! Scroll down for hints to both ways. +// one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways. // I AM NOT DONE @@ -45,27 +45,3 @@ mod tests { ); } } - - - - - - - - - - - - - - - - - -// One way to handle this is using a `match` statement on -// `item_quantity.parse::()` where the cases are `Ok(something)` and -// `Err(something)`. This pattern is very common in Rust, though, so there's -// a `?` operator that does pretty much what you would make that match statement -// do for you! Take a look at this section of the Error Handling chapter: -// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator -// and give it a try! diff --git a/exercises/error_handling/errors3.rs b/exercises/error_handling/errors3.rs index 35cd5c3d..460ac5c4 100644 --- a/exercises/error_handling/errors3.rs +++ b/exercises/error_handling/errors3.rs @@ -1,7 +1,8 @@ // errors3.rs // This is a program that is trying to use a completed version of the // `total_cost` function from the previous exercise. It's not working though! -// Why not? What should we do to fix it? Scroll for hints! +// Why not? What should we do to fix it? +// Execute `rustlings hint errors3` for hints! // I AM NOT DONE @@ -28,22 +29,3 @@ pub fn total_cost(item_quantity: &str) -> Result { Ok(qty * cost_per_item + processing_fee) } - - - - - - - - - - - - - - - - - - -// If other functions can return a `Result`, why shouldn't `main`? diff --git a/exercises/error_handling/errorsn.rs b/exercises/error_handling/errorsn.rs index cc90801a..30799430 100644 --- a/exercises/error_handling/errorsn.rs +++ b/exercises/error_handling/errorsn.rs @@ -13,7 +13,7 @@ // type goes where the question marks are, and how do we return // that type from the body of read_and_validate? // -// Scroll down for hints :) +// Execute `rustlings hint errorsn` for hints :) // I AM NOT DONE @@ -112,138 +112,3 @@ impl error::Error for CreationError { } } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// First hint: To figure out what type should go where the ??? is, take a look -// at the test helper function `test_with_str`, since it returns whatever -// `read_and_validate` returns and`test_with_str` has its signature fully -// specified. - - - - - - - - - - - - - - - - - - - - -// Next hint: There are three places in `read_and_validate` that we call a -// function that returns a `Result` (that is, the functions might fail). -// Apply the `?` operator on those calls so that we return immediately from -// `read_and_validate` if those function calls fail. - - - - - - - - - - - - - - - - - - - - -// Another hint: under the hood, the `?` operator calls `From::from` -// on the error value to convert it to a boxed trait object, a Box, -// which is polymorphic-- that means that lots of different kinds of errors -// can be returned from the same function because all errors act the same -// since they all implement the `error::Error` trait. -// Check out this section of the book: -// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator - - - - - - - - - - - - - - - - - - - - -// Another another hint: Note that because the `?` operator returns -// the *unwrapped* value in the `Ok` case, if we want to return a `Result` from -// `read_and_validate` for *its* success case, we'll have to rewrap a value -// that we got from the return value of a `?`ed call in an `Ok`-- this will -// look like `Ok(something)`. - - - - - - - - - - - - - - - - - - - - -// Another another another hint: `Result`s must be "used", that is, you'll -// get a warning if you don't handle a `Result` that you get in your -// function. Read more about that in the `std::result` module docs: -// https://doc.rust-lang.org/std/result/#results-must-be-used diff --git a/exercises/error_handling/option1.rs b/exercises/error_handling/option1.rs index 4e432a6f..5d81b150 100644 --- a/exercises/error_handling/option1.rs +++ b/exercises/error_handling/option1.rs @@ -2,7 +2,7 @@ // This example panics because the second time it calls `pop`, the `vec` // is empty, so `pop` returns `None`, and `unwrap` panics if it's called // on `None`. Handle this in a more graceful way than calling `unwrap`! -// Scroll down for hints :) +// Execute `rustlings hint option1` for hints :) // I AM NOT DONE @@ -29,31 +29,3 @@ mod tests { assert!(pop_too_much()); } } - - - - - - - - - - - - - - - - - - - - - - - -// Try using a `match` statement where the arms are `Some(thing)` and `None`. -// Or set a default value to print out if you get `None` by using the -// function `unwrap_or`. -// Or use an `if let` statement on the result of `pop()` to both destructure -// a `Some` value and only print out something if we have a value! diff --git a/exercises/error_handling/result1.rs b/exercises/error_handling/result1.rs index 52972dc4..b978001b 100644 --- a/exercises/error_handling/result1.rs +++ b/exercises/error_handling/result1.rs @@ -1,5 +1,5 @@ // result1.rs -// Make this test pass! Scroll down for hints :) +// Make this test pass! Execute `rustlings hint result1` for hints :) // I AM NOT DONE @@ -27,22 +27,3 @@ fn test_creation() { ); assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0)); } - - - - - - - - - - - - - - - - -// `PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result. -// It should be doing some checking, returning an `Err` result if those checks fail, and only -// returning an `Ok` result if those checks determine that everything is... okay :) diff --git a/exercises/functions/functions1.rs b/exercises/functions/functions1.rs index b9312ae3..31125278 100644 --- a/exercises/functions/functions1.rs +++ b/exercises/functions/functions1.rs @@ -1,46 +1,8 @@ // functions1.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint functions1` for hints :) // I AM NOT DONE fn main() { call_me(); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// This main function is calling a function that it expects to exist, but the -// function doesn't exist. It expects this function to have the name `call_me`. -// It expects this function to not take any arguments and not return a value. -// Sounds a lot like `main`, doesn't it? diff --git a/exercises/functions/functions2.rs b/exercises/functions/functions2.rs index c5b44180..108ba38b 100644 --- a/exercises/functions/functions2.rs +++ b/exercises/functions/functions2.rs @@ -1,5 +1,5 @@ // functions2.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint functions2` for hints :) // I AM NOT DONE @@ -12,33 +12,3 @@ fn call_me(num) { println!("Ring! Call number {}", i + 1); } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Rust requires that all parts of a function's signature have type annotations, -// but `call_me` is missing the type annotation of `num`. diff --git a/exercises/functions/functions3.rs b/exercises/functions/functions3.rs index 63bb5869..e3c1bf73 100644 --- a/exercises/functions/functions3.rs +++ b/exercises/functions/functions3.rs @@ -1,5 +1,5 @@ // functions3.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint functions3` for hints :) // I AM NOT DONE @@ -12,33 +12,3 @@ fn call_me(num: i32) { println!("Ring! Call number {}", i + 1); } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// This time, the function *declaration* is okay, but there's something wrong -// with the place where we're calling the function. diff --git a/exercises/functions/functions4.rs b/exercises/functions/functions4.rs index 91f62952..6bf46f08 100644 --- a/exercises/functions/functions4.rs +++ b/exercises/functions/functions4.rs @@ -1,5 +1,5 @@ // functions4.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint functions4` for hints :) // This store is having a sale where if the price is an even number, you get // 10 (money unit) off, but if it's an odd number, it's 3 (money unit) less. @@ -22,25 +22,3 @@ fn sale_price(price: i32) -> { fn is_even(num: i32) -> bool { num % 2 == 0 } - - - - - - - - - - - - - - - - - - - -// The error message points to line 12 and says it expects a type after the -// `->`. This is where the function's return type should be-- take a look at -// the `is_even` function for an example! diff --git a/exercises/functions/functions5.rs b/exercises/functions/functions5.rs index 696edee2..d22aa6c8 100644 --- a/exercises/functions/functions5.rs +++ b/exercises/functions/functions5.rs @@ -1,5 +1,5 @@ // functions5.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint functions5` for hints :) // I AM NOT DONE @@ -11,39 +11,3 @@ fn main() { fn square(num: i32) -> i32 { num * num; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// This is a really common error that can be fixed by removing one character. -// It happens because Rust distinguishes between expressions and statements: expressions return -// a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language. -// We want to return a value of `i32` type from the `square` function, but it is returning a `()` type... -// They are not the same. There are two solutions: -// 1. Add a `return` ahead of `num * num;` -// 2. remove `;`, make it to be `num * num` diff --git a/exercises/if/if1.rs b/exercises/if/if1.rs index da77e353..90867545 100644 --- a/exercises/if/if1.rs +++ b/exercises/if/if1.rs @@ -7,7 +7,7 @@ pub fn bigger(a: i32, b: i32) -> i32 { // Do not use: // - another function call // - additional variables - // Scroll down for hints. + // Execute `rustlings hint if1` for hints } // Don't mind this for now :) @@ -25,36 +25,3 @@ mod tests { assert_eq!(42, bigger(32, 42)); } } - - - - - - - - - - - - - - - - - - - - - - - - - -// It's possible to do this in one line if you would like! -// Some similar examples from other languages: -// - In C(++) this would be: `a > b ? a : b` -// - In Python this would be: `a if a > b else b` -// Remember in Rust that: -// - the `if` condition does not need to be surrounded by parentheses -// - `if`/`else` conditionals are expressions -// - Each condition is followed by a `{}` block. diff --git a/exercises/macros/macros1.rs b/exercises/macros/macros1.rs index f7b89e05..ed0dac85 100644 --- a/exercises/macros/macros1.rs +++ b/exercises/macros/macros1.rs @@ -1,5 +1,5 @@ // macros1.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint macros1` for hints :) // I AM NOT DONE @@ -12,55 +12,3 @@ macro_rules! my_macro { fn main() { my_macro(); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// When you call a macro, you need to add something special compared to a -// regular function call. If you're stuck, take a look at what's inside -// `my_macro`. diff --git a/exercises/macros/macros2.rs b/exercises/macros/macros2.rs index 7fe94297..d0be1236 100644 --- a/exercises/macros/macros2.rs +++ b/exercises/macros/macros2.rs @@ -1,5 +1,5 @@ // macros2.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint macros2` for hints :) // I AM NOT DONE @@ -12,64 +12,3 @@ macro_rules! my_macro { println!("Check out my macro!"); }; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Macros don't quite play by the same rules as the rest of Rust, in terms of -// what's available where. - - - - - - - - -// Unlike other things in Rust, the order of "where you define a macro" versus -// "where you use it" actually matters. diff --git a/exercises/macros/macros3.rs b/exercises/macros/macros3.rs index e9ef7f35..93a43113 100644 --- a/exercises/macros/macros3.rs +++ b/exercises/macros/macros3.rs @@ -1,5 +1,6 @@ // macros3.rs -// Make me compile, without taking the macro out of the module! Scroll down for hints :) +// Make me compile, without taking the macro out of the module! +// Execute `rustlings hint macros3` for hints :) // I AM NOT DONE @@ -14,64 +15,3 @@ mod macros { fn main() { my_macro!(); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// 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. - - - - - - - - -// The same trick also works on "extern crate" statements for crates that have -// exported macros, if you've seen any of those around. diff --git a/exercises/macros/macros4.rs b/exercises/macros/macros4.rs index 2893a157..3a748078 100644 --- a/exercises/macros/macros4.rs +++ b/exercises/macros/macros4.rs @@ -1,5 +1,5 @@ // macros4.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint macros4` for hints :) // I AM NOT DONE @@ -16,64 +16,3 @@ fn main() { my_macro!(); my_macro!(7777); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// You only need to add a single character to make this compile. - - - - - - - - - -// The way macros are written, it wants to see something between each -// "macro arm", so it can separate them. diff --git a/exercises/modules/modules1.rs b/exercises/modules/modules1.rs index 3f44968d..812dfeef 100644 --- a/exercises/modules/modules1.rs +++ b/exercises/modules/modules1.rs @@ -1,5 +1,5 @@ // modules1.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint modules1` for hints :) // I AM NOT DONE @@ -12,34 +12,3 @@ mod sausage_factory { fn main() { sausage_factory::make_sausage(); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Everything is private in Rust by default-- but there's a keyword we can use -// to make something public! The compiler error should point to the thing that -// needs to be public. diff --git a/exercises/modules/modules2.rs b/exercises/modules/modules2.rs index a3497cf4..fde439d1 100644 --- a/exercises/modules/modules2.rs +++ b/exercises/modules/modules2.rs @@ -1,5 +1,5 @@ // modules2.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint modules2` for hints :) // I AM NOT DONE @@ -25,25 +25,3 @@ fn main() { delicious_snacks::veggie ); } - - - - - - - - - - - - - - - - - -// The delicious_snacks module is trying to present an external -// interface (the `fruit` and `veggie` constants) that is different than -// its internal structure (the `fruits` and `veggies` modules and -// associated constants). It's almost there except for one keyword missing for -// each constant. diff --git a/exercises/move_semantics/move_semantics1.rs b/exercises/move_semantics/move_semantics1.rs index 625096da..e2f5876d 100644 --- a/exercises/move_semantics/move_semantics1.rs +++ b/exercises/move_semantics/move_semantics1.rs @@ -1,5 +1,5 @@ // move_semantics1.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute `rustlings hint move_semantics1` for hints :) // I AM NOT DONE @@ -24,21 +24,3 @@ fn fill_vec(vec: Vec) -> Vec { vec } - - - - - - - - - - - - - - - -// So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 11, -// right? The fix for this is going to be adding one keyword, and the addition is NOT on line 11 -// where the error is. diff --git a/exercises/move_semantics/move_semantics2.rs b/exercises/move_semantics/move_semantics2.rs index 28749e29..9233bb7e 100644 --- a/exercises/move_semantics/move_semantics2.rs +++ b/exercises/move_semantics/move_semantics2.rs @@ -1,5 +1,6 @@ // move_semantics2.rs -// Make me compile without changing line 10! Scroll down for hints :) +// Make me compile without changing line 10! +// Execute `rustlings hint move_semantics2` for hints :) // I AM NOT DONE @@ -25,31 +26,3 @@ fn fill_vec(vec: Vec) -> Vec { vec } - - - - - - - - - - - - - - -// So `vec0` is being *moved* into the function `fill_vec` when we call it on -// line 7, which means it gets dropped at the end of `fill_vec`, which means we -// can't use `vec0` again on line 10 (or anywhere else in `main` after the -// `fill_vec` call for that matter). We could fix this in a few ways, try them -// all! -// 1. Make another, separate version of the data that's in `vec0` and pass that -// to `fill_vec` instead. -// 2. Make `fill_vec` borrow its argument instead of taking ownership of it, -// and then copy the data within the function in order to return an owned -// `Vec` -// 3. Make `fill_vec` *mutably* borrow its argument (which will need to be -// mutable), modify it directly, then not return anything. Then you can get rid -// of `vec1` entirely -- note that this will change what gets printed by the -// first `println!` diff --git a/exercises/move_semantics/move_semantics3.rs b/exercises/move_semantics/move_semantics3.rs index a5b41b4a..43fef74f 100644 --- a/exercises/move_semantics/move_semantics3.rs +++ b/exercises/move_semantics/move_semantics3.rs @@ -1,7 +1,7 @@ // move_semantics3.rs // Make me compile without adding new lines-- just changing existing lines! // (no lines with multiple semicolons necessary!) -// Scroll down for hints :) +// Execute `rustlings hint move_semantics3` for hints :) // I AM NOT DONE @@ -24,24 +24,3 @@ fn fill_vec(vec: Vec) -> Vec { vec } - - - - - - - - - - - - - - - - - -// The difference between this one and the previous ones is that the first line -// of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can, -// instead of adding that line back, add `mut` in one place that will change -// an existing binding to be a mutable binding instead of an immutable one :) diff --git a/exercises/move_semantics/move_semantics4.rs b/exercises/move_semantics/move_semantics4.rs index b01e5935..a1c4a413 100644 --- a/exercises/move_semantics/move_semantics4.rs +++ b/exercises/move_semantics/move_semantics4.rs @@ -1,7 +1,8 @@ // move_semantics4.rs // Refactor this code so that instead of having `vec0` and creating the vector // in `fn main`, we instead create it within `fn fill_vec` and transfer the -// freshly created vector from fill_vec to its caller. Scroll for hints! +// freshly created vector from fill_vec to its caller. +// Execute `rustlings hint move_semantics4` for hints! // I AM NOT DONE @@ -27,24 +28,3 @@ fn fill_vec() -> Vec { vec } - - - - - - - - - - - - -// Stop reading whenever you feel like you have enough direction :) Or try -// doing one step and then fixing the compiler errors that result! -// So the end goal is to: -// - get rid of the first line in main that creates the new vector -// - so then `vec0` doesn't exist, so we can't pass it to `fill_vec` -// - we don't want to pass anything to `fill_vec`, so its signature should -// reflect that it does not take any arguments -// - since we're not creating a new vec in `main` anymore, we need to create -// a new vec in `fill_vec`, similarly to the way we did in `main` diff --git a/exercises/primitive_types/primitive_types3.rs b/exercises/primitive_types/primitive_types3.rs index bf2716a7..dfd6351c 100644 --- a/exercises/primitive_types/primitive_types3.rs +++ b/exercises/primitive_types/primitive_types3.rs @@ -1,6 +1,6 @@ // primitive_types3.rs // Create an array with at least 100 elements in it where the ??? is. -// Scroll down for hints! +// Execute `rustlings hint primitive_types3` for hints! // I AM NOT DONE @@ -13,37 +13,3 @@ fn main() { println!("Meh, I eat arrays like that for breakfast."); } } - - - - - - - - - - - - - - - - - - - - - - - - - - - -// There's a shorthand to initialize Arrays with a certain size that does not -// require you to type in 100 items (but you certainly can if you want!). -// For example, you can do: -// let array = ["Are we there yet?"; 10]; - -// Bonus: what are some other things you could have that would return true -// for `a.len() >= 100`? diff --git a/exercises/primitive_types/primitive_types4.rs b/exercises/primitive_types/primitive_types4.rs index e675aa12..ff1e2792 100644 --- a/exercises/primitive_types/primitive_types4.rs +++ b/exercises/primitive_types/primitive_types4.rs @@ -1,6 +1,6 @@ // primitive_types4.rs // Get a slice out of Array a where the ??? is so that the `if` statement -// returns true. Scroll down for hints!! +// returns true. Execute `rustlings hint primitive_types4` for hints!! // I AM NOT DONE @@ -12,59 +12,3 @@ fn main() { assert_eq!([2, 3, 4], nice_slice) } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book: -// https://doc.rust-lang.org/book/ch04-03-slices.html -// and use the starting and ending indices of the items in the Array -// that you want to end up in the slice. - -// If you're curious why the right hand of the `==` comparison does not -// have an ampersand for a reference since the left hand side is a -// reference, take a look at the Deref coercions section of the book: -// https://doc.rust-lang.org/book/ch15-02-deref.html diff --git a/exercises/primitive_types/primitive_types5.rs b/exercises/primitive_types/primitive_types5.rs index d8527ee5..680d8d23 100644 --- a/exercises/primitive_types/primitive_types5.rs +++ b/exercises/primitive_types/primitive_types5.rs @@ -1,6 +1,6 @@ // primitive_types5.rs // Destructure the `cat` tuple so that the println will work. -// Scroll down for hints! +// Execute `rustlings hint primitive_types5` for hints! // I AM NOT DONE @@ -10,38 +10,3 @@ fn main() { println!("{} is {} years old.", name, age); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Take a look at the Data Types -> The Tuple Type section of the book: -// https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type -// Particularly the part about destructuring (second to last example in the section). -// You'll need to make a pattern to bind `name` and `age` to the appropriate parts -// of the tuple. You can do it!! diff --git a/exercises/primitive_types/primitive_types6.rs b/exercises/primitive_types/primitive_types6.rs index 8fe9a36a..2bc817e9 100644 --- a/exercises/primitive_types/primitive_types6.rs +++ b/exercises/primitive_types/primitive_types6.rs @@ -1,7 +1,7 @@ // primitive_types6.rs // Use a tuple index to access the second element of `numbers`. // You can put this right into the `println!` where the ??? is. -// Scroll down for hints! +// Execute `rustlings hint primitive_types6` for hints! // I AM NOT DONE @@ -9,39 +9,3 @@ fn main() { let numbers = (1, 2, 3); println!("The second number is {}", ???); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// While you could use a destructuring `let` for the tuple here, try -// indexing into it instead, as explained in the last example of the -// Data Types -> The Tuple Type section of the book: -// https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type -// Now you have another tool in your toolbox! diff --git a/exercises/standard_library_types/arc1.rs b/exercises/standard_library_types/arc1.rs index effd28ab..04c169f1 100644 --- a/exercises/standard_library_types/arc1.rs +++ b/exercises/standard_library_types/arc1.rs @@ -2,7 +2,7 @@ // Make this code compile by filling in a value for `shared_numbers` where the // TODO comment is and creating an initial binding for `child_numbers` // somewhere. Try not to create any copies of the `numbers` Vec! -// Scroll down for hints :) +// Execute `rustlings help arc1` for hints :) // I AM NOT DONE @@ -29,29 +29,3 @@ fn main() { handle.join().unwrap(); } } - - - - - - - - - - - - - - - - - - - - -// Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order -// to avoid creating a copy of `numbers`, you'll need to create `child_numbers` -// inside the loop but still in the main thread. - -// `child_numbers` should be a clone of the Arc of the numbers instead of a -// thread-local copy of the numbers. diff --git a/exercises/standard_library_types/iterators2.rs b/exercises/standard_library_types/iterators2.rs index ea523e78..a1274a2d 100644 --- a/exercises/standard_library_types/iterators2.rs +++ b/exercises/standard_library_types/iterators2.rs @@ -3,7 +3,7 @@ // Step 1. Complete the `capitalize_first` function to pass the first two cases // Step 2. Apply the `capitalize_first` function to a vector of strings, ensuring that it returns a vector of strings as well // Step 3. Apply the `capitalize_first` function again to a list, but try and ensure it returns a single string -// As always, there are hints below! +// As always, there are hints if you execute `rustlings hint iterators2`! // I AM NOT DONE @@ -46,102 +46,3 @@ mod tests { assert_eq!(capitalized_words, "Hello World"); } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Step 1 -// You need to call something on `first` before it can be collected -// Currently its type is `char`. Have a look at the methods that are available on that type: -// https://doc.rust-lang.org/std/primitive.char.html - - - - - - - - - - - - - - - - - - - - - - - - - - -// Step 2 -// First you'll need to turn the Vec into an iterator -// Then you'll need to apply your function unto each item in the vector -// P.s. Don't forget to collect() at the end! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Step 3. -// This is very similar to the previous test. The only real change is that you will need to -// alter the type that collect is coerced into. For a bonus you could try doing this with a -// turbofish diff --git a/exercises/standard_library_types/iterators3.rs b/exercises/standard_library_types/iterators3.rs index 8fc57f2a..353cea62 100644 --- a/exercises/standard_library_types/iterators3.rs +++ b/exercises/standard_library_types/iterators3.rs @@ -4,8 +4,7 @@ // 1. Complete the divide function to get the first four tests to pass // 2. Uncomment the last two tests and get them to pass by filling in // values for `x` using `division_results`. -// Scroll down for a minor hint for part 2, and scroll down further for -// a major hint. +// Execute `rustlings hint iterators3` to get some hints! // Have fun :-) // I AM NOT DONE @@ -77,72 +76,3 @@ mod tests { } */ } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Minor hint: In each of the two cases in the match in main, you can create x with either -// a 'turbofish' or by hinting the type of x to the compiler. You may try both. - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Major hint: Have a look at the Iter trait and at the explanation of its collect function. -// Especially the part about Result is interesting. diff --git a/exercises/standard_library_types/iterators4.rs b/exercises/standard_library_types/iterators4.rs index 39be8bf6..b945613f 100644 --- a/exercises/standard_library_types/iterators4.rs +++ b/exercises/standard_library_types/iterators4.rs @@ -11,7 +11,7 @@ pub fn factorial(num: u64) -> u64 { // - additional variables // For the most fun don't use: // - recursion - // Scroll down for hints. + // Execute `rustlings hint iterators4` for hints. } #[cfg(test)] @@ -32,32 +32,3 @@ mod tests { assert_eq!(24, factorial(4)); } } - - - - - - - - - - - - - - - - - - - - - - - - - -// In an imperative language you might write a for loop to iterate through -// multiply the values into a mutable variable. Or you might write code more -// functionally with recursion and a match clause. But you can also use ranges -// and iterators to solve this in rust. diff --git a/exercises/strings/strings1.rs b/exercises/strings/strings1.rs index 33357344..80902444 100644 --- a/exercises/strings/strings1.rs +++ b/exercises/strings/strings1.rs @@ -1,5 +1,6 @@ // strings1.rs -// Make me compile without changing the function signature! Scroll down for hints :) +// Make me compile without changing the function signature! +// Execute `rustlings hint strings1` for hints ;) // I AM NOT DONE @@ -11,38 +12,3 @@ fn main() { fn current_favorite_color() -> String { "blue" } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// The `current_favorite_color` function is currently returning a string slice with the `'static` -// lifetime. We know this because the data of the string lives in our code itself -- it doesn't -// come from a file or user input or another program -- so it will live as long as our program -// lives. But it is still a string slice. There's one way to create a `String` by converting a -// string slice covered in the Strings chapter of the book, and another way that uses the `From` -// trait. diff --git a/exercises/strings/strings2.rs b/exercises/strings/strings2.rs index 3890cfee..5a2ce74a 100644 --- a/exercises/strings/strings2.rs +++ b/exercises/strings/strings2.rs @@ -1,5 +1,6 @@ // strings2.rs -// Make me compile without changing the function signature! Scroll down for hints :) +// Make me compile without changing the function signature! +// Execute `rustlings hint strings2` for hints :) // I AM NOT DONE @@ -15,32 +16,3 @@ fn main() { fn is_a_color_word(attempt: &str) -> bool { attempt == "green" || attempt == "blue" || attempt == "red" } - - - - - - - - - - - - - - - - - - - - - - - - - - -// Yes, it would be really easy to fix this by just changing the value bound to `word` to be a -// string slice instead of a `String`, wouldn't it?? There is a way to add one character to line -// 6, though, that will coerce the `String` into a string slice. diff --git a/exercises/tests/tests1.rs b/exercises/tests/tests1.rs index 1465e37c..b37cefa3 100644 --- a/exercises/tests/tests1.rs +++ b/exercises/tests/tests1.rs @@ -4,7 +4,7 @@ // rustlings run --test exercises/tests/tests1.rs // This test has a problem with it -- make the test compile! Make the test -// pass! Make the test fail! Scroll down for hints :) +// pass! Make the test fail! Execute `rustlings hint tests1` for hints :) // I AM NOT DONE @@ -15,37 +15,3 @@ mod tests { assert!(); } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// You don't even need to write any code to test -- you can just test values and run that, even -// though you wouldn't do that in real life :) `assert!` is a macro that needs an argument. -// Depending on the value of the argument, `assert!` will do nothing (in which case the test will -// pass) or `assert!` will panic (in which case the test will fail). So try giving different values -// to `assert!` and see which ones compile, which ones pass, and which ones fail :) diff --git a/exercises/tests/tests2.rs b/exercises/tests/tests2.rs index 81e30e06..0d981ad1 100644 --- a/exercises/tests/tests2.rs +++ b/exercises/tests/tests2.rs @@ -1,6 +1,6 @@ // tests2.rs // This test has a problem with it -- make the test compile! Make the test -// pass! Make the test fail! Scroll down for hints :) +// pass! Make the test fail! Execute `rustlings hint tests2` for hints :) // I AM NOT DONE @@ -11,36 +11,3 @@ mod tests { assert_eq!(); } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Like the previous exercise, you don't need to write any code to get this test to compile and -// run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two -// values that are equal! Try giving it two arguments that are different! Try giving it two values -// that are of different types! Try switching which argument comes first and which comes second! diff --git a/exercises/tests/tests3.rs b/exercises/tests/tests3.rs index af480958..693b8aa5 100644 --- a/exercises/tests/tests3.rs +++ b/exercises/tests/tests3.rs @@ -1,7 +1,8 @@ // tests3.rs // This test isn't testing our function -- make it do that in such a way that // the test passes. Then write a second test that tests whether we get the result -// we expect to get when we call `is_even(5)`. Scroll down for hints! +// we expect to get when we call `is_even(5)`. +// Execute `rustlings hint tests3` for hints :) // I AM NOT DONE @@ -18,28 +19,3 @@ mod tests { assert!(); } } - - - - - - - - - - - - - - - - - - - - - - -// You can call a function right where you're passing arguments to `assert!` -- so you could do -// something like `assert!(having_fun())`. If you want to check that you indeed get false, you -// can negate the result of what you're doing using `!`, like `assert!(!having_fun())`. diff --git a/exercises/threads/threads1.rs b/exercises/threads/threads1.rs index d23553ec..288ddd14 100644 --- a/exercises/threads/threads1.rs +++ b/exercises/threads/threads1.rs @@ -1,8 +1,8 @@ // threads1.rs -// Make this compile! Scroll down for hints :) The idea is the thread -// spawned on line 19 is completing jobs while the main thread is +// Make this compile! Execute `rustlings hint threads1` for hints :) +// The idea is the thread spawned on line 19 is completing jobs while the main thread is // monitoring progress until 10 jobs are completed. If you see 6 lines -// of "waiting..." and the program ends without timing out the playground, +// of "waiting..." and the program ends without timing out when running, // you've got it :) // I AM NOT DONE @@ -29,69 +29,3 @@ fn main() { thread::sleep(Duration::from_millis(500)); } } - - - - - - - - - - - - - - -// `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` -// so we'll need to also use another type that will only allow one thread to -// 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 -// and keep scrolling if you'd like more hints :) - - - - - - - - - - -// Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like: -// `let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));` -// Similar to the code in the example in the book that happens after the text -// that says "We can use Arc to fix this.". If not, give that a try! If you -// do and would like more hints, keep scrolling!! - - - - - - - - - - - - -// Make sure neither of your threads are holding onto the lock of the mutex -// while they are sleeping, since this will prevent the other thread from -// being allowed to get the lock. Locks are automatically released when -// they go out of scope. - -// Ok, so, real talk, this was actually tricky for *me* to do too. And -// I could see a lot of different problems you might run into, so at this -// point I'm not sure which one you've hit :) Please see a few possible -// answers on https://github.com/carols10cents/rustlings/issues/3 -- -// mine is a little more complicated because I decided I wanted to see -// the number of jobs currently done when I was checking the status. - -// Please open an issue if you're still running into a problem that -// these hints are not helping you with, or if you've looked at the sample -// answers and don't understand why they work and yours doesn't. - -// If you've learned from the sample solutions, I encourage you to come -// back to this exercise and try it again in a few days to reinforce -// what you've learned :) diff --git a/exercises/variables/variables1.rs b/exercises/variables/variables1.rs index 174ad80a..5ddc37d5 100644 --- a/exercises/variables/variables1.rs +++ b/exercises/variables/variables1.rs @@ -1,5 +1,5 @@ // variables1.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :) // About this `I AM NOT DONE` thing: // We sometimes encourage you to keep trying things on a given exercise, @@ -12,38 +12,3 @@ fn main() { x = 5; println!("x has the value {}", x); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Hint: The declaration on line 5 is missing a keyword that is needed in Rust -// to create a new variable binding. diff --git a/exercises/variables/variables2.rs b/exercises/variables/variables2.rs index e3c3b768..7774a8fb 100644 --- a/exercises/variables/variables2.rs +++ b/exercises/variables/variables2.rs @@ -1,5 +1,5 @@ // variables2.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute the command `rustlings hint variables2` if you want a hint :) // I AM NOT DONE @@ -11,39 +11,3 @@ fn main() { println!("Not ten!"); } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// The compiler message is saying that Rust cannot infer the type that the -// variable binding `x` has with what is given here. -// What happens if you annotate line 5 with a type annotation? -// What if you give x a value? -// What if you do both? -// What type should x be, anyway? -// What if x is the same type as 10? What if it's a different type? diff --git a/exercises/variables/variables3.rs b/exercises/variables/variables3.rs index 7e3fd933..07b1a521 100644 --- a/exercises/variables/variables3.rs +++ b/exercises/variables/variables3.rs @@ -1,5 +1,5 @@ // variables3.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute the command `rustlings hint variables3` if you want a hint :) // I AM NOT DONE @@ -9,37 +9,3 @@ fn main() { x = 5; println!("Number {}", x); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// In Rust, variable bindings are immutable by default. But here we're trying -// to reassign a different value to x! There's a keyword we can use to make -// a variable binding mutable instead. diff --git a/exercises/variables/variables4.rs b/exercises/variables/variables4.rs index 33eca9e2..77f1e9ab 100644 --- a/exercises/variables/variables4.rs +++ b/exercises/variables/variables4.rs @@ -1,5 +1,5 @@ // variables4.rs -// Make me compile! Scroll down for hints :) +// Make me compile! Execute the command `rustlings hint variables4` if you want a hint :) // I AM NOT DONE @@ -7,41 +7,3 @@ fn main() { let x: i32; println!("Number {}", x); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Oops! In this exercise, we have a variable binding that we've created on -// line 5, and we're trying to use it on line 6, but we haven't given it a -// value. We can't print out something that isn't there; try giving x a value! -// This is an error that can cause bugs that's very easy to make in any -// programming language -- thankfully the Rust compiler has caught this for us! diff --git a/info.toml b/info.toml index d908c9eb..c7ad1e2d 100644 --- a/info.toml +++ b/info.toml @@ -1,241 +1,612 @@ # VARIABLES [[exercises]] +name = "variables1" path = "exercises/variables/variables1.rs" mode = "compile" +hint = """ +Hint: The declaration on line 5 is missing a keyword that is needed in Rust +to create a new variable binding.""" [[exercises]] +name = "variables2" path = "exercises/variables/variables2.rs" mode = "compile" +hint = """ +The compiler message is saying that Rust cannot infer the type that the +variable binding `x` has with what is given here. +What happens if you annotate line 5 with a type annotation? +What if you give x a value? +What if you do both? +What type should x be, anyway? +What if x is the same type as 10? What if it's a different type?""" [[exercises]] +name = "variables3" path = "exercises/variables/variables3.rs" mode = "compile" +hint = """ +In Rust, variable bindings are immutable by default. But here we're trying +to reassign a different value to x! There's a keyword we can use to make +a variable binding mutable instead.""" [[exercises]] +name = "variables4" path = "exercises/variables/variables4.rs" mode = "compile" +hint = """ +Oops! In this exercise, we have a variable binding that we've created on +line 5, and we're trying to use it on line 6, but we haven't given it a +value. We can't print out something that isn't there; try giving x a value! +This is an error that can cause bugs that's very easy to make in any +programming language -- thankfully the Rust compiler has caught this for us!""" # IF [[exercises]] +name = "if1" path = "exercises/if/if1.rs" mode = "test" +hint = """ +It's possible to do this in one line if you would like! +Some similar examples from other languages: +- In C(++) this would be: `a > b ? a : b` +- In Python this would be: `a if a > b else b` +Remember in Rust that: +- the `if` condition does not need to be surrounded by parentheses +- `if`/`else` conditionals are expressions +- Each condition is followed by a `{}` block.""" # FUNCTIONS [[exercises]] +name = "functions1" path = "exercises/functions/functions1.rs" mode = "compile" +hint = """ +This main function is calling a function that it expects to exist, but the +function doesn't exist. It expects this function to have the name `call_me`. +It expects this function to not take any arguments and not return a value. +Sounds a lot like `main`, doesn't it?""" [[exercises]] +name = "functions2" path = "exercises/functions/functions2.rs" mode = "compile" +hint = """ +Rust requires that all parts of a function's signature have type annotations, +but `call_me` is missing the type annotation of `num`.""" [[exercises]] +name = "functions3" path = "exercises/functions/functions3.rs" mode = "compile" +hint = """ +This time, the function *declaration* is okay, but there's something wrong +with the place where we're calling the function.""" [[exercises]] +name = "functions4" path = "exercises/functions/functions4.rs" mode = "compile" +hint = """ +The error message points to line 12 and says it expects a type after the +`->`. This is where the function's return type should be-- take a look at +the `is_even` function for an example!""" [[exercises]] +name = "functions5" path = "exercises/functions/functions5.rs" mode = "compile" +hint = """ +This is a really common error that can be fixed by removing one character. +It happens because Rust distinguishes between expressions and statements: expressions return +a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language. +We want to return a value of `i32` type from the `square` function, but it is returning a `()` type... +They are not the same. There are two solutions: +1. Add a `return` ahead of `num * num;` +2. remove `;`, make it to be `num * num`""" # TEST 1 [[exercises]] +name = "test1" path = "exercises/test1.rs" mode = "test" +hint = "No hints this time ;)" # PRIMITIVE TYPES [[exercises]] +name = "primitive_types1" path = "exercises/primitive_types/primitive_types1.rs" mode = "compile" +hint = "No hints this time ;)" [[exercises]] +name = "primitive_types2" path = "exercises/primitive_types/primitive_types2.rs" mode = "compile" +hint = "No hints this time ;)" [[exercises]] +name = "primitive_types3" path = "exercises/primitive_types/primitive_types3.rs" mode = "compile" +hint = """ +There's a shorthand to initialize Arrays with a certain size that does not +require you to type in 100 items (but you certainly can if you want!). +For example, you can do: +let array = ["Are we there yet?"; 10]; + +Bonus: what are some other things you could have that would return true +for `a.len() >= 100`?""" [[exercises]] +name = "primitive_types4" path = "exercises/primitive_types/primitive_types4.rs" mode = "test" +hint = """ +Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book: +https://doc.rust-lang.org/book/ch04-03-slices.html +and use the starting and ending indices of the items in the Array +that you want to end up in the slice. + +If you're curious why the right hand of the `==` comparison does not +have an ampersand for a reference since the left hand side is a +reference, take a look at the Deref coercions section of the book: +https://doc.rust-lang.org/book/ch15-02-deref.html""" [[exercises]] +name = "primitive_types5" path = "exercises/primitive_types/primitive_types5.rs" mode = "compile" +hint = """ +Take a look at the Data Types -> The Tuple Type section of the book: +https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type +Particularly the part about destructuring (second to last example in the section). +You'll need to make a pattern to bind `name` and `age` to the appropriate parts +of the tuple. You can do it!!""" [[exercises]] +name = "primitive_types6" path = "exercises/primitive_types/primitive_types6.rs" mode = "compile" +hint = """ +While you could use a destructuring `let` for the tuple here, try +indexing into it instead, as explained in the last example of the +Data Types -> The Tuple Type section of the book: +https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type +Now you have another tool in your toolbox!""" # STRUCTS [[exercises]] +name = "structs1" path = "exercises/structs/structs1.rs" mode = "test" +hint = "No hints this time ;)" [[exercises]] +name = "structs2" path = "exercises/structs/structs2.rs" mode = "test" +hint = "No hints this time ;)" # STRINGS [[exercises]] +name = "strings1" path = "exercises/strings/strings1.rs" mode = "compile" +hint = """ +The `current_favorite_color` function is currently returning a string slice with the `'static` +lifetime. We know this because the data of the string lives in our code itself -- it doesn't +come from a file or user input or another program -- so it will live as long as our program +lives. But it is still a string slice. There's one way to create a `String` by converting a +string slice covered in the Strings chapter of the book, and another way that uses the `From` +trait.""" [[exercises]] +name = "strings2" path = "exercises/strings/strings2.rs" mode = "compile" +hint = """ +Yes, it would be really easy to fix this by just changing the value bound to `word` to be a +string slice instead of a `String`, wouldn't it?? There is a way to add one character to line +6, though, that will coerce the `String` into a string slice.""" # TEST 2 [[exercises]] +name = "test2" path = "exercises/test2.rs" mode = "compile" +hint = "No hints this time ;)" # ENUMS [[exercises]] +name = "enums1" path = "exercises/enums/enums1.rs" mode = "compile" +hint = """ +Hint: The declaration of the enumeration type has not been defined yet.""" [[exercises]] +name = "enums2" path = "exercises/enums/enums2.rs" mode = "compile" +hint = """ +Hint: you can create enumerations that have different variants with different types +such as no data, anonymous structs, a single string, tuples, ...etc""" [[exercises]] +name = "enums3" path = "exercises/enums/enums3.rs" mode = "test" +hint = "No hints this time ;)" # TESTS [[exercises]] +name = "tests1" path = "exercises/tests/tests1.rs" mode = "test" +hint = """ +You don't even need to write any code to test -- you can just test values and run that, even +though you wouldn't do that in real life :) `assert!` is a macro that needs an argument. +Depending on the value of the argument, `assert!` will do nothing (in which case the test will +pass) or `assert!` will panic (in which case the test will fail). So try giving different values +to `assert!` and see which ones compile, which ones pass, and which ones fail :)""" [[exercises]] +name = "tests2" path = "exercises/tests/tests2.rs" mode = "test" +hint = """ +Like the previous exercise, you don't need to write any code to get this test to compile and +run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two +values that are equal! Try giving it two arguments that are different! Try giving it two values +that are of different types! Try switching which argument comes first and which comes second!""" [[exercises]] +name = "tests3" path = "exercises/tests/tests3.rs" mode = "test" +hint = """ +You can call a function right where you're passing arguments to `assert!` -- so you could do +something like `assert!(having_fun())`. If you want to check that you indeed get false, you +can negate the result of what you're doing using `!`, like `assert!(!having_fun())`.""" # TEST 3 [[exercises]] +name = "test3" path = "exercises/test3.rs" mode = "test" +hint = "No hints this time ;)" # MODULES [[exercises]] +name = "modules1" path = "exercises/modules/modules1.rs" mode = "compile" +hint = """ +Everything is private in Rust by default-- but there's a keyword we can use +to make something public! The compiler error should point to the thing that +needs to be public.""" [[exercises]] +name = "modules2" path = "exercises/modules/modules2.rs" mode = "compile" +hint = """ +The delicious_snacks module is trying to present an external +interface (the `fruit` and `veggie` constants) that is different than +its internal structure (the `fruits` and `veggies` modules and +associated constants). It's almost there except for one keyword missing for +each constant.""" # MACROS [[exercises]] +name = "macros1" path = "exercises/macros/macros1.rs" mode = "compile" +hint = """ +When you call a macro, you need to add something special compared to a +regular function call. If you're stuck, take a look at what's inside +`my_macro`.""" [[exercises]] +name = "macros2" path = "exercises/macros/macros2.rs" mode = "compile" +hint = """ +Macros don't quite play by the same rules as the rest of Rust, in terms of +what's available where. + +Unlike other things in Rust, the order of "where you define a macro" versus +"where you use it" actually matters.""" [[exercises]] +name = "macros3" path = "exercises/macros/macros3.rs" mode = "compile" +hint = """ +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. + +The same trick also works on "extern crate" statements for crates that have +exported macros, if you've seen any of those around.""" [[exercises]] +name = "macros4" path = "exercises/macros/macros4.rs" mode = "compile" - +hint = """ +You only need to add a single character to make this compile. +The way macros are written, it wants to see something between each +"macro arm", so it can separate them.""" # TEST 4 [[exercises]] +name = "test4" path = "exercises/test4.rs" mode = "compile" +hint = "No hints this time ;)" # MOVE SEMANTICS [[exercises]] +name = "move_semantics1" path = "exercises/move_semantics/move_semantics1.rs" mode = "compile" +hint = """ +So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 11, +right? The fix for this is going to be adding one keyword, and the addition is NOT on line 11 +where the error is.""" [[exercises]] +name = "move_semantics2" path = "exercises/move_semantics/move_semantics2.rs" mode = "compile" +hint = """ +So `vec0` is being *moved* into the function `fill_vec` when we call it on +line 7, which means it gets dropped at the end of `fill_vec`, which means we +can't use `vec0` again on line 10 (or anywhere else in `main` after the +`fill_vec` call for that matter). We could fix this in a few ways, try them +all! +1. Make another, separate version of the data that's in `vec0` and pass that + to `fill_vec` instead. +2. Make `fill_vec` borrow its argument instead of taking ownership of it, + and then copy the data within the function in order to return an owned + `Vec` +3. Make `fill_vec` *mutably* borrow its argument (which will need to be + mutable), modify it directly, then not return anything. Then you can get rid + of `vec1` entirely -- note that this will change what gets printed by the + first `println!`""" [[exercises]] +name = "move_semantics3" path = "exercises/move_semantics/move_semantics3.rs" mode = "compile" +hint = """ +The difference between this one and the previous ones is that the first line +of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can, +instead of adding that line back, add `mut` in one place that will change +an existing binding to be a mutable binding instead of an immutable one :)""" [[exercises]] +name = "move_semantics4" path = "exercises/move_semantics/move_semantics4.rs" mode = "compile" +hint = """ +Stop reading whenever you feel like you have enough direction :) Or try +doing one step and then fixing the compiler errors that result! +So the end goal is to: + - get rid of the first line in main that creates the new vector + - so then `vec0` doesn't exist, so we can't pass it to `fill_vec` + - we don't want to pass anything to `fill_vec`, so its signature should + reflect that it does not take any arguments + - since we're not creating a new vec in `main` anymore, we need to create + a new vec in `fill_vec`, similarly to the way we did in `main`""" # ERROR HANDLING [[exercises]] +name = "errors1" path = "exercises/error_handling/errors1.rs" mode = "test" +hint = """ +`Err` is one of the variants of `Result`, so what the 2nd test is saying +is that `generate_nametag_text` should return a `Result` instead of an +`Option`. + +To make this change, you'll need to: + - update the return type in the function signature to be a Result that + could be the variants `Ok(String)` and `Err(String)` + - change the body of the function to return `Ok(stuff)` where it currently + returns `Some(stuff)` + - change the body of the function to return `Err(error message)` where it + currently returns `None` + - change the first test to expect `Ok(stuff)` where it currently expects + `Some(stuff)`.""" [[exercises]] +name = "errors2" path = "exercises/error_handling/errors2.rs" mode = "test" +hint = """ +One way to handle this is using a `match` statement on +`item_quantity.parse::()` where the cases are `Ok(something)` and +`Err(something)`. This pattern is very common in Rust, though, so there's +a `?` operator that does pretty much what you would make that match statement +do for you! Take a look at this section of the Error Handling chapter: +https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator +and give it a try!""" [[exercises]] +name = "errors3" path = "exercises/error_handling/errors3.rs" mode = "test" +hint = """ +If other functions can return a `Result`, why shouldn't `main`?""" [[exercises]] +name = "errorsn" path = "exercises/error_handling/errorsn.rs" mode = "test" +hint = """ +First hint: To figure out what type should go where the ??? is, take a look +at the test helper function `test_with_str`, since it returns whatever +`read_and_validate` returns and`test_with_str` has its signature fully +specified. + + +Next hint: There are three places in `read_and_validate` that we call a +function that returns a `Result` (that is, the functions might fail). +Apply the `?` operator on those calls so that we return immediately from +`read_and_validate` if those function calls fail. + + +Another hint: under the hood, the `?` operator calls `From::from` +on the error value to convert it to a boxed trait object, a Box, +which is polymorphic-- that means that lots of different kinds of errors +can be returned from the same function because all errors act the same +since they all implement the `error::Error` trait. +Check out this section of the book: +https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator + + +Another another hint: Note that because the `?` operator returns +the *unwrapped* value in the `Ok` case, if we want to return a `Result` from +`read_and_validate` for *its* success case, we'll have to rewrap a value +that we got from the return value of a `?`ed call in an `Ok`-- this will +look like `Ok(something)`. + + +Another another another hint: `Result`s must be "used", that is, you'll +get a warning if you don't handle a `Result` that you get in your +function. Read more about that in the `std::result` module docs: +https://doc.rust-lang.org/std/result/#results-must-be-used""" # OPTIONS / RESULTS [[exercises]] +name = "option1" path = "exercises/error_handling/option1.rs" mode = "test" +hint = """ +Try using a `match` statement where the arms are `Some(thing)` and `None`. +Or set a default value to print out if you get `None` by using the +function `unwrap_or`. +Or use an `if let` statement on the result of `pop()` to both destructure +a `Some` value and only print out something if we have a value!""" [[exercises]] +name = "result1" path = "exercises/error_handling/result1.rs" mode = "test" +hint = """ +`PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result. +It should be doing some checking, returning an `Err` result if those checks fail, and only +returning an `Ok` result if those checks determine that everything is... okay :)""" # STANDARD LIBRARY TYPES [[exercises]] +name = "arc1" path = "exercises/standard_library_types/arc1.rs" mode = "compile" +hint = """ +Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order +to avoid creating a copy of `numbers`, you'll need to create `child_numbers` +inside the loop but still in the main thread. + +`child_numbers` should be a clone of the Arc of the numbers instead of a +thread-local copy of the numbers.""" [[exercises]] +name = "iterators2" path = "exercises/standard_library_types/iterators2.rs" mode = "test" +hint = """ +Step 1 +You need to call something on `first` before it can be collected +Currently its type is `char`. Have a look at the methods that are available on that type: +https://doc.rust-lang.org/std/primitive.char.html + + +Step 2 +First you'll need to turn the Vec into an iterator +Then you'll need to apply your function unto each item in the vector +P.s. Don't forget to collect() at the end! + + +Step 3. +This is very similar to the previous test. The only real change is that you will need to +alter the type that collect is coerced into. For a bonus you could try doing this with a +turbofish""" [[exercises]] +name = "iterators3" path = "exercises/standard_library_types/iterators3.rs" mode = "test" +hint = """ +Minor hint: In each of the two cases in the match in main, you can create x with either +a 'turbofish' or by hinting the type of x to the compiler. You may try both. + +Major hint: Have a look at the Iter trait and at the explanation of its collect function. +Especially the part about Result is interesting.""" [[exercises]] +name = "iterators4" path = "exercises/standard_library_types/iterators4.rs" mode = "test" +hint = """ +In an imperative language you might write a for loop to iterate through +multiply the values into a mutable variable. Or you might write code more +functionally with recursion and a match clause. But you can also use ranges +and iterators to solve this in rust.""" # THREADS [[exercises]] +name = "threads1" path = "exercises/threads/threads1.rs" mode = "compile" +hint = """ +`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` +so we'll need to also use another type that will only allow one thread to +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 +and keep reading if you'd like more hints :) + + +Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like: +`let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));` +Similar to the code in the example in the book that happens after the text +that says "We can use Arc to fix this.". If not, give that a try! If you +do and would like more hints, keep reading!! + + +Make sure neither of your threads are holding onto the lock of the mutex +while they are sleeping, since this will prevent the other thread from +being allowed to get the lock. Locks are automatically released when +they go out of scope. + +Ok, so, real talk, this was actually tricky for *me* to do too. And +I could see a lot of different problems you might run into, so at this +point I'm not sure which one you've hit :) + +Please open an issue if you're still running into a problem that +these hints are not helping you with, or if you've looked at the sample +answers and don't understand why they work and yours doesn't. + +If you've learned from the sample solutions, I encourage you to come +back to this exercise and try it again in a few days to reinforce +what you've learned :)""" diff --git a/src/exercise.rs b/src/exercise.rs index f27b5453..b6c28da4 100644 --- a/src/exercise.rs +++ b/src/exercise.rs @@ -28,8 +28,10 @@ pub struct ExerciseList { #[derive(Deserialize)] pub struct Exercise { + pub name: String, pub path: PathBuf, pub mode: Mode, + pub hint: String, } #[derive(PartialEq, Debug)] @@ -128,8 +130,10 @@ mod test { fn test_clean() { File::create(&temp_file()).unwrap(); let exercise = Exercise { + name: String::from("example"), path: PathBuf::from("example.rs"), mode: Mode::Test, + hint: String::from(""), }; exercise.clean(); assert!(!Path::new(&temp_file()).exists()); @@ -138,8 +142,10 @@ mod test { #[test] fn test_pending_state() { let exercise = Exercise { + name: "pending_exercise".into(), path: PathBuf::from("tests/fixture/state/pending_exercise.rs"), mode: Mode::Compile, + hint: String::new(), }; let state = exercise.state(); @@ -177,8 +183,10 @@ mod test { #[test] fn test_finished_exercise() { let exercise = Exercise { + name: "finished_exercise".into(), path: PathBuf::from("tests/fixture/state/finished_exercise.rs"), mode: Mode::Compile, + hint: String::new(), }; assert_eq!(exercise.state(), State::Done); diff --git a/src/main.rs b/src/main.rs index e42dff4a..d1d0d6d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,8 +25,13 @@ fn main() { SubCommand::with_name("run") .alias("r") .about("Runs/Tests a single exercise") - .arg(Arg::with_name("file").required(true).index(1)) - .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")), + .arg(Arg::with_name("name").required(true).index(1)), + ) + .subcommand( + SubCommand::with_name("hint") + .alias("h") + .about("Returns a hint for the current exercise") + .arg(Arg::with_name("name").required(true).index(1)), ) .get_matches(); @@ -55,26 +60,32 @@ fn main() { let exercises = toml::from_str::(toml_str).unwrap().exercises; if let Some(ref matches) = matches.subcommand_matches("run") { - let filename = matches.value_of("file").unwrap_or_else(|| { - println!("Please supply a file name!"); - std::process::exit(1); - }); + let name = matches.value_of("name").unwrap(); - let matching_exercise = |e: &&Exercise| { - Path::new(filename) - .canonicalize() - .map(|p| p.ends_with(&e.path)) - .unwrap_or(false) - }; + let matching_exercise = |e: &&Exercise| name == e.name; let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| { - println!("No exercise found for your file name!"); + println!("No exercise found for your given name!"); std::process::exit(1) }); run(&exercise).unwrap_or_else(|_| std::process::exit(1)); } + if let Some(ref matches) = matches.subcommand_matches("hint") { + let name = matches.value_of("name").unwrap(); + + let exercise = exercises + .iter() + .find(|e| name == e.name) + .unwrap_or_else(|| { + println!("No exercise found for your given name!"); + std::process::exit(1) + }); + + println!("{}", exercise.hint); + } + if matches.subcommand_matches("verify").is_some() { verify(&exercises).unwrap_or_else(|_| std::process::exit(1)); } diff --git a/tests/fixture/failure/info.toml b/tests/fixture/failure/info.toml index f4e7c0cb..e5949f9b 100644 --- a/tests/fixture/failure/info.toml +++ b/tests/fixture/failure/info.toml @@ -1,7 +1,11 @@ [[exercises]] +name = "compFailure" path = "compFailure.rs" mode = "compile" +hint = "" [[exercises]] +name = "testFailure" path = "testFailure.rs" -mode = "test" \ No newline at end of file +mode = "test" +hint = "Hello!" diff --git a/tests/fixture/success/info.toml b/tests/fixture/success/info.toml index e255db9f..68d35388 100644 --- a/tests/fixture/success/info.toml +++ b/tests/fixture/success/info.toml @@ -1,7 +1,11 @@ [[exercises]] +name = "compSuccess" path = "compSuccess.rs" mode = "compile" +hint = """""" [[exercises]] +name = "testSuccess" path = "testSuccess.rs" -mode = "test" \ No newline at end of file +mode = "test" +hint = """""" diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 897cd2af..754aa635 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -43,7 +43,7 @@ fn verify_all_failure() { fn run_single_compile_success() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "compSuccess.rs"]) + .args(&["r", "compSuccess"]) .current_dir("tests/fixture/success/") .assert() .success(); @@ -53,7 +53,7 @@ fn run_single_compile_success() { fn run_single_compile_failure() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "compFailure.rs"]) + .args(&["r", "compFailure"]) .current_dir("tests/fixture/failure/") .assert() .code(1); @@ -63,7 +63,7 @@ fn run_single_compile_failure() { fn run_single_test_success() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "testSuccess.rs"]) + .args(&["r", "testSuccess"]) .current_dir("tests/fixture/success/") .assert() .success(); @@ -73,7 +73,7 @@ fn run_single_test_success() { fn run_single_test_failure() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "testFailure.rs"]) + .args(&["r", "testFailure"]) .current_dir("tests/fixture/failure/") .assert() .code(1); @@ -109,6 +109,17 @@ fn run_single_test_no_exercise() { .code(1); } +#[test] +fn get_hint_for_single_test() { + Command::cargo_bin("rustlings") + .unwrap() + .args(&["h", "testFailure"]) + .current_dir("tests/fixture/failure") + .assert() + .code(0) + .stdout("Hello!\n"); +} + #[test] fn all_exercises_require_confirmation() { for exercise in glob("exercises/**/*.rs").unwrap() {