diff --git a/exercises/18_closures/closures1.rs b/exercises/18_closures/closures1.rs index 91396208..2e36e9b8 100644 --- a/exercises/18_closures/closures1.rs +++ b/exercises/18_closures/closures1.rs @@ -10,8 +10,6 @@ // // Execute `rustlings hint closures1` or use the `hint` watch subcommand for a hint. -// I AM NOT DONE - trait Doorman { fn greet_customer(&self, customer_name: &str); diff --git a/rustlings-macros/info.toml b/rustlings-macros/info.toml index c1f4fe98..72c9b4bb 100644 --- a/rustlings-macros/info.toml +++ b/rustlings-macros/info.toml @@ -881,8 +881,7 @@ https://doc.rust-lang.org/book/ch11-01-writing-tests.html#checking-for-panics-wi [[exercises]] name = "closures1" -path = "exercises/18_closures/closures1.rs" -mode = "compile" +dir = "18_closures" hint = """ Self is a concept that is only used in struct/enum methods. diff --git a/solutions/18_closures/closures1.rs b/solutions/18_closures/closures1.rs new file mode 100644 index 00000000..d85682c4 --- /dev/null +++ b/solutions/18_closures/closures1.rs @@ -0,0 +1,61 @@ +// closures1.rs +// +// "Why do we even need closures?" is a question that gets asked from time to time. +// While it's true that most things that closures can do can also be done with +// regular old structs and enums, closures can make things a lot more clear with a lot +// less clutter compared to structs. +// +// Below is a good example of how one could implement a capturing closure using structs, +// and how closures simplifies this greatly. +// +// Execute `rustlings hint closures1` or use the `hint` watch subcommand for a hint. + +trait Doorman { + fn greet_customer(&self, customer_name: &str); +} + +struct GreeterWithState<'a> { + greeting: &'a str, +} + +impl Doorman for GreeterWithState<'_> { + fn greet_customer(&self, customer_name: &str) { + println!("{}, {}?", self.greeting, customer_name); + } +} + +fn greet_customers(doorman: impl Doorman) { + doorman.greet_customer("Bill"); + doorman.greet_customer("Alex"); + doorman.greet_customer("John"); + doorman.greet_customer("Jessie"); +} + +fn greet_customers_closure(doorman: impl Fn(&str)) { + doorman("Bill"); + doorman("Alex"); + doorman("John"); + doorman("Jessie"); +} + +fn main() { + let greeting = String::from("Hello! How are you"); + + // Method 1 for passing in functions with state. + // Just create a struct, store the state, and add a method. + // If you need to be generic, it can be a trait method. + let doorman = GreeterWithState { + greeting: &greeting, + }; + greet_customers(doorman); + + // Method 2 for passing in functions with state. + // Notice that the body of this closure is exactly the same + // as GreeterWithState's Doorman implementation. + // + // This makes things much cleaner with less clutter, but + // we are forgetting something very important. + greet_customers_closure(|customer_name| { + println!("{}, {}?", greeting, customer_name); // Capture greeting by reference + }) +}