Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add functions6.rs and move_semantics6.rs exercises about closures #1748

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions dev/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down Expand Up @@ -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" },
Expand Down
3 changes: 2 additions & 1 deletion exercises/02_functions/README.md
Original file line number Diff line number Diff line change
@@ -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)
19 changes: 19 additions & 0 deletions exercises/02_functions/functions6.rs
Original file line number Diff line number Diff line change
@@ -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
}
25 changes: 25 additions & 0 deletions exercises/06_move_semantics/move_semantics6.rs
Original file line number Diff line number Diff line change
@@ -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);
}
2 changes: 1 addition & 1 deletion exercises/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
26 changes: 26 additions & 0 deletions rustlings-macros/info.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand Down Expand Up @@ -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]]
Expand Down
9 changes: 9 additions & 0 deletions solutions/02_functions/functions6.rs
Original file line number Diff line number Diff line change
@@ -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);
}
14 changes: 14 additions & 0 deletions solutions/06_move_semantics/move_semantics6.rs
Original file line number Diff line number Diff line change
@@ -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);
}