diff --git a/exercises/closures/README.md b/exercises/closures/README.md new file mode 100644 index 00000000..66a34789 --- /dev/null +++ b/exercises/closures/README.md @@ -0,0 +1,17 @@ +# Closures + +Closures are a common programming concept found in many languages, but are primarily +associated with 'functional' programming styles. Closure are anonymous functions +(i.e. unlike regular functions, they don't have a name) that may access some variables +from their enclosing scope (they 'close' over their scope, capturing variables). + +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. + +## Further information + +- [Closures: Anonymous Functions that Can Capture Their Environment](https://doc.rust-lang.org/book/ch13-01-closures.html) \ No newline at end of file diff --git a/exercises/closures/closures1.rs b/exercises/closures/closures1.rs new file mode 100644 index 00000000..05feb46f --- /dev/null +++ b/exercises/closures/closures1.rs @@ -0,0 +1,21 @@ +// closures1.rs +// Closures are anonymous functions, but they can be assigned to a variable +// so that they can be used later on +// make me compile and pass + +// Execute `rustlings hint closures1` for hints! + +// I AM NOT DONE + +fn main() {} + +#[cfg(test)] +mod tests { + use super::*; + + # [test] + fn test_closure() { + let closure = ; + assert_eq!("I'm a closure",closure()); + } +} \ No newline at end of file diff --git a/exercises/closures/closures2.rs b/exercises/closures/closures2.rs new file mode 100644 index 00000000..048ee405 --- /dev/null +++ b/exercises/closures/closures2.rs @@ -0,0 +1,24 @@ +// closure2.rs +// What is the difference between a closure and a function? Can you get this code +// to compile? + +// Execute `rustlings hint closures2` for hints! + +// I AM NOT DONE + +fn output(closure) { + println!("What am I?"); + closure(); +} + +fn main() { + + fn actual() { + println!("I'm actually a function") + } + + let actual_fn = actual; + let closure = || println!("I'm a closure"); + output(closure); + output(actual_fn); +} \ No newline at end of file diff --git a/exercises/closures/closures3.rs b/exercises/closures/closures3.rs new file mode 100644 index 00000000..93c030cd --- /dev/null +++ b/exercises/closures/closures3.rs @@ -0,0 +1,24 @@ +// closure3.rs +// What is the difference between a closure and a function, part II? Can you get this code +// to compile? + +// Execute `rustlings hint closures3` for hints! + +// I AM NOT DONE + +fn main() { + let my_name = String::from("Lim Lady"); + + fn actual() { + println!("my name is: {}", my_name); + } + + let actual_fn = actual; + let closure = || { + println!("my name is: {}", my_name); + }; + + println!("Who am I?"); + actual_fn(); + closure(); +} \ No newline at end of file diff --git a/exercises/closures/closures4.rs b/exercises/closures/closures4.rs new file mode 100644 index 00000000..da10c15a --- /dev/null +++ b/exercises/closures/closures4.rs @@ -0,0 +1,34 @@ +// closure4.rs +// Where are you going to use closures? Where the context defines the code +// 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. +// https://doc.rust-lang.org/stable/std/primitive.slice.html#method.sort_by + +// Execute `rustlings hint closures4` for hints! + +// I AM NOT DONE + +fn alphabetize(list: &mut Vec<&str>) { + list.sort_by(); +} + +fn main() { + let mut list = vec!("Oliver","Tarquinn","Bertrude"); + println!("before {:?}",list); + alphabetize(& mut list); + println!("after {:?}",list); +} + +#[cfg(test)] +mod tests { + use super::*; + + # [test] + fn test_alphabetize() { + let mut list = vec!("Oliver","Tarquinn","Bertrude"); + assert_eq!(vec!("Bertrude","Oliver","Tarquinn"),alphabetize(&mut list)); + } +} \ No newline at end of file diff --git a/exercises/closures/closures5.rs b/exercises/closures/closures5.rs new file mode 100644 index 00000000..b0f54f67 --- /dev/null +++ b/exercises/closures/closures5.rs @@ -0,0 +1,44 @@ +// 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.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! + +// I AM NOT DONE + +fn count_letters(animals: &Vec<&str>) -> Vec{ + // the compiler should help you figure out what signature to use + // after you annotate it with one that fails. + 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 + // https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.fold + animals.iter().fold(0, sum_closure) +} + +fn main() { + let animals= vec!["cat","fish","horse"]; + println!("animals: {:?}",animals); + println!("length: {:?}", count_letters(&animals)); + println!("total: {:?}", sum_letters(&animals)); +} + +#[cfg(test)] +mod tests { + use super::*; + + # [test] + fn test_() { + let animals= vec!["cat","fish","horse"]; + assert_eq!(vec![3,4,5], count_letters(&animals)); + assert_eq!(12, sum_letters(&animals)); + } +} \ No newline at end of file diff --git a/exercises/closures/mod.rs b/exercises/closures/mod.rs new file mode 100644 index 00000000..e49f3704 --- /dev/null +++ b/exercises/closures/mod.rs @@ -0,0 +1,5 @@ +mod closures1; +mod closures2; +mod closures3; +mod closures4; +mod closures5; diff --git a/exercises/collections/mod.rs b/exercises/collections/mod.rs index f46c1424..ee2b4423 100644 --- a/exercises/collections/mod.rs +++ b/exercises/collections/mod.rs @@ -1,4 +1 @@ -mod hashmap1; -mod hashmap2; -mod vec1; -mod vec2; +mod closures1; diff --git a/exercises/mod.rs b/exercises/mod.rs index 914f7381..130a2204 100644 --- a/exercises/mod.rs +++ b/exercises/mod.rs @@ -25,3 +25,4 @@ mod threads; mod traits; mod variables; mod lifetimes; +mod closures; diff --git a/info.toml b/info.toml index 2f9786e2..4c8ec94c 100644 --- a/info.toml +++ b/info.toml @@ -136,6 +136,50 @@ 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`""" +# CLOSURES + +[[exercises]] +name = "closures1" +path = "exercises/closures/closures1.rs" +mode = "test" +hint = """ +Take a look at this section of the book: https://doc.rust-lang.org/book/ch13-01-closures.html""" + +[[exercises]] +name = "closures2" +path = "exercises/closures/closures2.rs" +mode = "compile" +hint = """ +A bit taxing, but these should help: +https://doc.rust-lang.org/rust-by-example/fn/closures/input_parameters.html +https://doc.rust-lang.org/rust-by-example/fn/closures/anonymity.html +https://doc.rust-lang.org/rust-by-example/fn/closures/input_functions.html""" + +[[exercises]] +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?""" + +[[exercises]] +name = "closures4" +path = "exercises/closures/closures4.rs" +mode = "test" +hint = """ +Don't try to actually implement any comparison other than using cmp: +https://doc.rust-lang.org/stable/std/cmp/trait.Ord.html#tymethod.cmp +e.g. x.cmp(y)""" + +[[exercises]] +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.""" + # IF [[exercises]]