diff --git a/dev/Cargo.toml b/dev/Cargo.toml index 29a557a0..6ec0f110 100644 --- a/dev/Cargo.toml +++ b/dev/Cargo.toml @@ -26,6 +26,8 @@ bin = [ { name = "functions4_sol", path = "../solutions/02_functions/functions4.rs" }, { name = "functions5", path = "../exercises/02_functions/functions5.rs" }, { name = "functions5_sol", path = "../solutions/02_functions/functions5.rs" }, + { name = "functions6", path = "../exercises/02_functions/functions6.rs" }, + { name = "functions6_sol", path = "../solutions/02_functions/functions6.rs" }, { name = "if1", path = "../exercises/03_if/if1.rs" }, { name = "if1_sol", path = "../solutions/03_if/if1.rs" }, { name = "if2", path = "../exercises/03_if/if2.rs" }, @@ -60,6 +62,8 @@ bin = [ { name = "move_semantics4_sol", path = "../solutions/06_move_semantics/move_semantics4.rs" }, { name = "move_semantics5", path = "../exercises/06_move_semantics/move_semantics5.rs" }, { name = "move_semantics5_sol", path = "../solutions/06_move_semantics/move_semantics5.rs" }, + { name = "move_semantics6", path = "../exercises/06_move_semantics/move_semantics6.rs" }, + { name = "move_semantics6_sol", path = "../solutions/06_move_semantics/move_semantics6.rs" }, { name = "structs1", path = "../exercises/07_structs/structs1.rs" }, { name = "structs1_sol", path = "../solutions/07_structs/structs1.rs" }, { name = "structs2", path = "../exercises/07_structs/structs2.rs" }, diff --git a/exercises/02_functions/README.md b/exercises/02_functions/README.md index 6662d0da..63ea0e82 100644 --- a/exercises/02_functions/README.md +++ b/exercises/02_functions/README.md @@ -1,8 +1,9 @@ # Functions Here, you'll learn how to write functions and how the Rust compiler can help you debug errors even -in more complex code. +in more complex code. You will also learn what is the difference with closures. ## Further information - [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html) +- [Closures](https://doc.rust-lang.org/book/ch13-01-closures.html) diff --git a/exercises/02_functions/functions6.rs b/exercises/02_functions/functions6.rs new file mode 100644 index 00000000..53294a76 --- /dev/null +++ b/exercises/02_functions/functions6.rs @@ -0,0 +1,19 @@ +// functions6.rs +// +// Here you can practice special functions called `closures`, that can capture +// variables of their parent context. +// Fix the code below to make it compile, without changing the two closure +// definitions. +// +// Execute `rustlings hint functions6` or use the `hint` watch subcommand for +// some hints. + +fn main() { + // TODO: ensure the definition of captured variable + let closure_1 = |input_var: u32| -> u32 {input_var + outer_var}; + println!("Closure#1 returns {}", closure_1(5)); + + let closure_2 = |input_var| println!("Closure#2 (input_var {})", input_var); + closure_2(2); + closure_2("5"); // TODO: look at the captured variable type here +} diff --git a/exercises/06_move_semantics/move_semantics6.rs b/exercises/06_move_semantics/move_semantics6.rs new file mode 100644 index 00000000..c437ca65 --- /dev/null +++ b/exercises/06_move_semantics/move_semantics6.rs @@ -0,0 +1,25 @@ +// move_semantics6.rs +// +// Here you will practice how mutable/immutable borrowing works in the context +// of a closure. +// +// Try to fix this code to make it compile and not panic. +// You can't change anything except removing 1 line. +// +// Execute `rustlings hint move_semantics7` or use the `hint` watch subcommand +// for a hint. + +fn main() { + let mut counter = 0; + + let mut increment = || { + counter += 1; + println!("counter equals {}", counter); + }; + + increment(); + let _reborrowed_counter = &counter; // TODO: figure out where to put this borrowing instruction + increment(); + + assert_eq!(counter, 2); +} diff --git a/exercises/README.md b/exercises/README.md index 237f2f1e..66003eff 100644 --- a/exercises/README.md +++ b/exercises/README.md @@ -3,7 +3,7 @@ | Exercise | Book Chapter | | ---------------------- | ------------------- | | variables | §3.1 | -| functions | §3.3 | +| functions | §3.3, §13.1 | | if | §3.5 | | primitive_types | §3.2, §4.3 | | vecs | §8.1 | diff --git a/rustlings-macros/info.toml b/rustlings-macros/info.toml index e7055981..303135f6 100644 --- a/rustlings-macros/info.toml +++ b/rustlings-macros/info.toml @@ -187,6 +187,20 @@ There are two solutions: 1. Add the `return` keyword before `num * num;` 2. Remove the semicolon `;` after `num * num`""" +[[exercises]] +name = "functions6" +dir = "02_functions" +test = false +hint = """ +Hint FIX #1: Closures can capture variables defined in the outer context. + +Hint FIX #2: Closures can infer both input and returned types, when they are not +specified in the signature. But the closure cannot be reused with different +input types. + +Read more about closures in the rust book dedicated section: +https://doc.rust-lang.org/book/ch13-01-closures.html""" + # IF [[exercises]] @@ -391,6 +405,18 @@ The first problem is that `get_char` is taking ownership of the string. So Once you've fixed that, `string_uppercase`'s function signature will also need to be adjusted.""" +[[exercises]] +name = "move_semantics6" +dir = "06_move_semantics" +test = false +hint = """ +When a closure captures a variable to modify it, it actually borrows that variable +as a mutable reference. In this exercise, the closure mutably borrows the `counter` +variable, thus, any attempt to borrow `counter` between closure calls leads to an error. + +You cannot immutably borrow a variable if a mutable closure is +called later in the scope.""" + # STRUCTS [[exercises]] diff --git a/solutions/02_functions/functions6.rs b/solutions/02_functions/functions6.rs new file mode 100644 index 00000000..c3fc0671 --- /dev/null +++ b/solutions/02_functions/functions6.rs @@ -0,0 +1,9 @@ +fn main() { + let outer_var = 1; + let closure_1 = |input_var: u32| -> u32 { input_var + outer_var }; + println!("Closure#1 returns {}", closure_1(5)); + + let closure_2 = |input_var| println!("Closure#2 (input_var {})", input_var); + closure_2(2); + closure_2(5); +} diff --git a/solutions/06_move_semantics/move_semantics6.rs b/solutions/06_move_semantics/move_semantics6.rs new file mode 100644 index 00000000..57a59231 --- /dev/null +++ b/solutions/06_move_semantics/move_semantics6.rs @@ -0,0 +1,14 @@ +fn main() { + let mut counter = 0; + + let mut increment = || { + counter += 1; + println!("counter equals {}", counter); + }; + + increment(); + increment(); + let _reborrowed_counter = &counter; + + assert_eq!(counter, 2); +}