mirror of
https://github.com/rust-lang/rustlings.git
synced 2026-01-11 05:09:19 +00:00
feat: added closures exercises in closure directory
Closures as a separate exercises appeared to be missing, so I added some. Have placed them in the watch order after functions, which seemed reasonable.
This commit is contained in:
parent
600a498187
commit
d36d7b32e5
@ -9,8 +9,8 @@ Closures are often used as arguments to higher order functions (functions which
|
||||
take other functions as parameters), e.g. map(), filter(), reduce() et al on iterators,
|
||||
but aren't restricted to these cases.
|
||||
|
||||
Rust's ownership model means that we might have to do something extra when declaring
|
||||
closures which other languages don't require.
|
||||
Rust's ownership model means that we may need to think about how captured values
|
||||
are treated: copied, moved, or borrowed immutably or mutably.
|
||||
|
||||
## Further information
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// closures1.rs
|
||||
// Closures are anonymous functions, but they can be assigned to a variable
|
||||
// so that they can be used later on
|
||||
// so that they can be used later on.
|
||||
// make me compile and pass
|
||||
|
||||
// Execute `rustlings hint closures1` for hints!
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
// closure4.rs
|
||||
// Where are you going to use closures? Where the context defines the code
|
||||
// Where are you going to use closures? Where the context defines the logic
|
||||
// you want some other code to invoke. So, unlike functions or methods, closures
|
||||
// are for when the code is not generally useful, or attached to a
|
||||
// type, but is specific to the context you are defining it in. Closures can
|
||||
// define parameters, just like functions, but these are defined by the context
|
||||
// it is intended to run in, where the actual arguments will be supplied.
|
||||
// define parameters, just like functions, but these are specified by the context
|
||||
// the closure is intended to be invoked in, where the actual arguments will be supplied.
|
||||
// https://doc.rust-lang.org/stable/std/primitive.slice.html#method.sort_by
|
||||
|
||||
// Execute `rustlings hint closures4` for hints!
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
// closure5.rs
|
||||
// These are some fairly common uses of closures on iterator methods
|
||||
// https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.map
|
||||
// https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.reduce
|
||||
// https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.fold
|
||||
// my original version used 'reduce()' instead of 'fold()' but why would that
|
||||
// be unsuitable for a sum function in Rust (specifically)?
|
||||
|
||||
// Execute `rustlings hint closures5` for hints!
|
||||
|
||||
@ -12,16 +11,19 @@
|
||||
fn count_letters(animals: &Vec<&str>) -> Vec<usize>{
|
||||
// the compiler should help you figure out what signature to use
|
||||
// after you annotate it with one that fails.
|
||||
// TODO: fill in this line with closure that compiles and passes the test.
|
||||
let count_closure = ;
|
||||
animals.iter().map(count_closure).collect()
|
||||
}
|
||||
|
||||
fn sum_letters(animals: &Vec<&str>) -> usize {
|
||||
let sum_closure =
|
||||
let animals = count_letters(animals);
|
||||
// pay close attention to the where clause in the function signature
|
||||
// pay close attention to the where clause in the function signatures
|
||||
// https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.reduce
|
||||
// https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.fold
|
||||
animals.iter().fold(0, sum_closure)
|
||||
// TODO: change the next 2 lines to compile and pass the test.
|
||||
let sum_closure = |x: &usize, y: &usize| &(x + y);
|
||||
animals.iter().reduce(sum_closure).unwrap().to_owned()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -36,7 +38,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
# [test]
|
||||
fn test_() {
|
||||
fn test_closures() {
|
||||
let animals= vec!["cat","fish","horse"];
|
||||
assert_eq!(vec![3,4,5], count_letters(&animals));
|
||||
assert_eq!(12, sum_letters(&animals));
|
||||
|
||||
25
exercises/closures/closures6.rs
Normal file
25
exercises/closures/closures6.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// closure6.rs
|
||||
// The compiler will take care of inferring the correct types for
|
||||
// closures you write:
|
||||
// https://doc.rust-lang.org/book/ch13-01-closures.html#capturing-the-environment-with-closures
|
||||
// But if you want to make sure that values are inaccessible after
|
||||
// the closure, they can be moved rather than borrowed using the 'move' keyword.
|
||||
// Make me compile!
|
||||
|
||||
// Execute `rustlings hint closures6` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn move_it() {
|
||||
let who_wants_to = vec!["I want to ", "He wants to ", "They want to "];
|
||||
let do_what = String::from("move it");
|
||||
|
||||
let chorus: Vec<String> = who_wants_to.iter().map( move |&who| who.to_owned() + do_what.as_str() + ", " + do_what.as_str() + ".").collect();
|
||||
println!("{:?}",chorus);
|
||||
|
||||
println!("{:?}!",do_what.to_uppercase());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
move_it();
|
||||
}
|
||||
@ -3,3 +3,4 @@ mod closures2;
|
||||
mod closures3;
|
||||
mod closures4;
|
||||
mod closures5;
|
||||
mod closures6;
|
||||
|
||||
24
info.toml
24
info.toml
@ -160,14 +160,15 @@ name = "closures3"
|
||||
path = "exercises/closures/closures3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
The compiler has got you covered with this. After all, why IS it called a closure?"""
|
||||
The compiler has got you covered with this. After all, why IS it called a closure?
|
||||
If you actually want to make it work, you can add a parameter to the function."""
|
||||
|
||||
[[exercises]]
|
||||
name = "closures4"
|
||||
path = "exercises/closures/closures4.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Don't try to actually implement any comparison other than using cmp:
|
||||
Don't try to actually implement any comparison logic other than invoking cmp:
|
||||
https://doc.rust-lang.org/stable/std/cmp/trait.Ord.html#tymethod.cmp
|
||||
e.g. x.cmp(y)"""
|
||||
|
||||
@ -176,9 +177,22 @@ name = "closures5"
|
||||
path = "exercises/closures/closures5.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Honestly this was hard to write. Getting the signatures of closures right can be tough.
|
||||
Pay close attention to the documentation linked to in the exercise and which type
|
||||
parameters are the same in the function signatures."""
|
||||
Getting the signatures of closures right can be tough. I don't think you can write
|
||||
any version that fulfills the tests using 'reduce()': you can never return a borrow
|
||||
of a value owned by a called function.
|
||||
You need to replace 'reduce()' with a different function call, update the closure
|
||||
so that it matches the signature of this new call, and change the code to return
|
||||
the correct type from the sum_letters function. (Using 'sum()' is cheating!)
|
||||
Pay close attention to the documentation linked to in the exercise: which type
|
||||
parameters are the same in the function signatures, and which are different."""
|
||||
|
||||
[[exercises]]
|
||||
name = "closures6"
|
||||
path = "exercises/closures/closures6.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
There are two ways to solve this, neither is difficult and both involve just removing
|
||||
the offending part. If you're thinking hard, you've missed the point."""
|
||||
|
||||
# IF
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user