From 1c27aeead908a7179b48f2bd70e43acfc730ffea Mon Sep 17 00:00:00 2001 From: Enrico Date: Wed, 1 Nov 2023 22:36:58 +0100 Subject: [PATCH 1/2] feat: add functions6.rs and move_semantics6.rs exercises about closures --- exercises/02_functions/README.md | 3 +- exercises/02_functions/functions6.rs | 20 +++++++++++++ .../06_move_semantics/move_semantics6.rs | 27 +++++++++++++++++ exercises/README.md | 2 +- rustlings-macros/info.toml | 29 +++++++++++++++++++ 5 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 exercises/02_functions/functions6.rs create mode 100644 exercises/06_move_semantics/move_semantics6.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..4a418785 --- /dev/null +++ b/exercises/02_functions/functions6.rs @@ -0,0 +1,20 @@ +// 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. + +// I AM NOT DONE + +fn main() { + 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/exercises/06_move_semantics/move_semantics6.rs b/exercises/06_move_semantics/move_semantics6.rs new file mode 100644 index 00000000..ec17358f --- /dev/null +++ b/exercises/06_move_semantics/move_semantics6.rs @@ -0,0 +1,27 @@ +// 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. + +// I AM NOT DONE + +fn main() { + let mut counter = 0; + + let mut increment = || { + counter += 1; + println!("counter: {}", counter); + }; + + increment(); + let _reborrowed_counter = &counter; + 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 c1342d68..72a3162b 100644 --- a/rustlings-macros/info.toml +++ b/rustlings-macros/info.toml @@ -187,6 +187,21 @@ There are two solutions: 1. Add the `return` keyword before `num * num;` 2. Remove the semicolon `;` after `num * num`""" +[[exercises]] +name = "functions6" +path = "exercises/02_functions/functions6.rs" +mode = "compile" +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 +406,20 @@ 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" +path = "exercises/06_move_semantics/move_semantics6.rs" +mode = "compile" +hint = """ +When a closure capture a variable to modify it, it borrows that variable as a +mutable reference. In this exercise, as the closure mutably borrows `counter` +and is called later, any attempt to reborrow `counter` in between will lead to +an error. + +You cannot immutably borrow a variable if a mutable closure is +called later in the scope. +""" + # STRUCTS [[exercises]] From e59c65cf4594d7ee30f5c9e10cddb3438a74722c Mon Sep 17 00:00:00 2001 From: Enrico Date: Sun, 29 Sep 2024 20:34:29 +0200 Subject: [PATCH 2/2] chore: Refactored to adhere to new rustlings version --- dev/Cargo.toml | 4 ++++ exercises/02_functions/functions6.rs | 5 ++--- .../06_move_semantics/move_semantics6.rs | 6 ++---- rustlings-macros/info.toml | 21 ++++++++----------- solutions/02_functions/functions6.rs | 9 ++++++++ .../06_move_semantics/move_semantics6.rs | 14 +++++++++++++ 6 files changed, 40 insertions(+), 19 deletions(-) create mode 100644 solutions/02_functions/functions6.rs create mode 100644 solutions/06_move_semantics/move_semantics6.rs 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/functions6.rs b/exercises/02_functions/functions6.rs index 4a418785..53294a76 100644 --- a/exercises/02_functions/functions6.rs +++ b/exercises/02_functions/functions6.rs @@ -8,13 +8,12 @@ // Execute `rustlings hint functions6` or use the `hint` watch subcommand for // some hints. -// I AM NOT DONE - 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"); + 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 index ec17358f..c437ca65 100644 --- a/exercises/06_move_semantics/move_semantics6.rs +++ b/exercises/06_move_semantics/move_semantics6.rs @@ -9,18 +9,16 @@ // Execute `rustlings hint move_semantics7` or use the `hint` watch subcommand // for a hint. -// I AM NOT DONE - fn main() { let mut counter = 0; let mut increment = || { counter += 1; - println!("counter: {}", counter); + println!("counter equals {}", counter); }; increment(); - let _reborrowed_counter = &counter; + let _reborrowed_counter = &counter; // TODO: figure out where to put this borrowing instruction increment(); assert_eq!(counter, 2); diff --git a/rustlings-macros/info.toml b/rustlings-macros/info.toml index 72a3162b..77c84f13 100644 --- a/rustlings-macros/info.toml +++ b/rustlings-macros/info.toml @@ -189,8 +189,8 @@ There are two solutions: [[exercises]] name = "functions6" -path = "exercises/02_functions/functions6.rs" -mode = "compile" +dir = "02_functions" +test = false hint = """ Hint FIX #1: Closures can capture variables defined in the outer context. @@ -199,8 +199,7 @@ 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 -""" +https://doc.rust-lang.org/book/ch13-01-closures.html""" # IF @@ -408,17 +407,15 @@ to be adjusted.""" [[exercises]] name = "move_semantics6" -path = "exercises/06_move_semantics/move_semantics6.rs" -mode = "compile" +dir = "06_move_semantics" +test = false hint = """ -When a closure capture a variable to modify it, it borrows that variable as a -mutable reference. In this exercise, as the closure mutably borrows `counter` -and is called later, any attempt to reborrow `counter` in between will lead to -an error. +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. -""" +called later in the scope.""" # STRUCTS 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); +}