X-Git-Url: https://git.ralfj.de/rust-101.git/blobdiff_plain/562558d25054c5be82f11acad0fbe53699de5b1c..a52087dc8f244861d144229b04e64f934ed1d03f:/workspace/src/part11.rs?ds=sidebyside diff --git a/workspace/src/part11.rs b/workspace/src/part11.rs index cc2a252..a93ad07 100644 --- a/workspace/src/part11.rs +++ b/workspace/src/part11.rs @@ -1,97 +1,65 @@ -// Rust-101, Part 11: Trait Objects, Box, Rc, Lifetime bounds -// ========================================================== +// Rust-101, Part 11: Trait Objects, Box, Lifetime bounds +// ====================================================== -mod callbacks { - // For now, we just decide that the callbacks have an argument of type `i32`. - struct CallbacksV1 { - callbacks: Vec, - } - - /* struct CallbacksV2 { - callbacks: Vec, - } */ - pub struct Callbacks { - callbacks: Vec>, - } +// For now, we just decide that the callbacks have an argument of type `i32`. +struct CallbacksV1 { + callbacks: Vec, +} - impl Callbacks { - // Now we can provide some functions. The constructor should be straight-forward. - pub fn new() -> Self { - unimplemented!() - } +/* struct CallbacksV2 { + callbacks: Vec, +} */ - // Registration simply stores the callback. - pub fn register(&mut self, callback: Box) { - unimplemented!() - } +pub struct Callbacks { + callbacks: Vec>, +} - // And here we call all the stored callbacks. - pub fn call(&mut self, val: i32) { - // Since they are of type `FnMut`, we need to mutably iterate. Notice that boxes dereference implicitly. - for callback in self.callbacks.iter_mut() { - unimplemented!() - } - } +impl Callbacks { + // Now we can provide some functions. The constructor should be straight-forward. + pub fn new() -> Self { + unimplemented!() } - // Now we are ready for the demo. - pub fn demo(c: &mut Callbacks) { - c.register(Box::new(|val| println!("Callback 1: {}", val))); - c.call(0); - - let mut count: usize = 0; - c.register(Box::new(move |val| { - count = count+1; - println!("Callback 2, {}. time: {}", count, val); - } )); - c.call(1); c.call(2); + // Registration simply stores the callback. + pub fn register(&mut self, callback: Box) { + self.callbacks.push(callback); } -} -// Remember to edit `main.rs` to run the demo. -pub fn main() { - let mut c = callbacks::Callbacks::new(); - callbacks::demo(&mut c); -} - -mod callbacks_clone { - - use std::rc::Rc; - - #[derive(Clone)] - pub struct Callbacks { - callbacks: Vec>, + // We can also write a generic version of `register`, such that it will be instantiated with some concrete closure type `F` + // and do the creation of the `Box` and the conversion from `F` to `FnMut(i32)` itself. + + pub fn register_generic(&mut self, callback: F) { + unimplemented!() } - impl Callbacks { - pub fn new() -> Self { - unimplemented!() - } - - // For the `register` function, we don't actually have to use trait objects in the argument. - - pub fn register(&mut self, callback: F) { + // And here we call all the stored callbacks. + pub fn call(&mut self, val: i32) { + // Since they are of type `FnMut`, we need to mutably iterate. + for callback in self.callbacks.iter_mut() { unimplemented!() } - - pub fn call(&mut self, val: i32) { - // We only need a shared iterator here. `Rc` also implicitly dereferences, so we can simply call the callback. - for callback in self.callbacks.iter() { - unimplemented!() - } - } } +} + +// Now we are ready for the demo. Remember to edit `main.rs` to run it. +pub fn main() { + let mut c = Callbacks::new(); + c.register(Box::new(|val| println!("Callback 1: {}", val))); + c.call(0); - // The demo works just as above. Our counting callback doesn't work anymore though, because we are using `Fn` now. - fn demo(c: &mut Callbacks) { - c.register(|val| println!("Callback 1: {}", val)); - c.call(0); c.call(1); + { + let mut count: usize = 0; + c.register_generic(move |val| { + count = count+1; + println!("Callback 2: {} ({}. time)", val, count); + } ); } + c.call(1); c.call(2); } -// **Exercise 11.1**: We made the arbitrary choice of using `i32` for the arguments. Generalize the data-structures above -// to work with an arbitrary type `T` that's passed to the callbacks. Since you need to call multiple callbacks with the -// same `t: T`, you will either have to restrict `T` to `Copy` types, or pass a borrow. +// **Exercise 11.1**: We made the arbitrary choice of using `i32` for the arguments. Generalize the data structures above +// to work with an arbitrary type `T` that's passed to the callbacks. Since you need to call multiple callbacks with the +// same `t: T`, you will either have to restrict `T` to `Copy` types, or pass a reference.