pub trait Explainable { fn do_explain(&self)-> String; } pub trait HasAccount { fn get_account(&self)-> String; fn change_account(&mut self, new_value: &str); } pub struct Person { name: String, account: String } impl Explainable for Person { fn do_explain(&self)-> String { return self.name.clone() + " " + self.account.as_str() } } impl HasAccount for Person { fn change_account(&mut self, new_value: &str) { self.account = new_value.to_string(); } fn get_account(&self)-> String { return self.account.clone(); } } fn change_accounts<'a>(persons: impl Iterator<Item = &'a mut Person>) { for p in persons { println!("Changing person: {}", p.name); let mut new_str= String::with_capacity(100); new_str.push_str(&p.account); new_str.push_str("_020"); p.change_account(&new_str); } } fn change_accounts2<'a>(persons: impl Iterator<Item = &'a mut dyn HasAccount>) { for p in persons { let mut new_str = String::with_capacity(100); new_str.push_str(&p.get_account()); new_str.push_str("_020"); p.change_account(&new_str); } } fn change_accounts3<'a, I>(persons: I) where I: IntoIterator<Item = &'a mut dyn HasAccount>, { for p in persons { let mut new_str = String::with_capacity(100); new_str.push_str(&p.get_account()); new_str.push_str("_020"); p.change_account(&new_str); } } fn change_accounts4<'a, I>(persons: I) where I: IntoIterator<Item = &'a mut Box<dyn HasAccount>>, { for p in persons { let mut new_str = String::with_capacity(100); new_str.push_str(&p.get_account()); new_str.push_str("_020"); p.change_account(&new_str); } } // Trait with both traits trait Entity: Explainable + HasAccount {} impl<T: Explainable + HasAccount> Entity for T {} fn explain_all<'a>(items: impl IntoIterator<Item = &'a Box<dyn Entity>>) { for item in items { println!("{}", item.do_explain()); } } fn change_all<'a>(items: impl IntoIterator<Item = &'a mut Box<dyn Entity>>) { for item in items { let mut new_str = item.get_account(); new_str.push_str("_mod"); item.change_account(&new_str); } } fn get_boxed_entities1() -> Vec<Box<dyn Entity>> { vec![ Box::new(Person { name: "Piet".into(), account: "abc".into() }), Box::new(Person { name: "Klaas".into(), account: "xyz".into() }), ] } // return an iterator fn get_boxed_entities2() -> impl Iterator<Item = Box<dyn Entity>> { return vec![ Box::new(Person { name: "Piet".into(), account: "abc".into() }), Box::new(Person { name: "Klaas".into(), account: "xyz".into() }), ] .into_iter() .map(|p| p as Box<dyn Entity>) } fn main() { println!("Hello, world!"); let mut persons = vec![ Person { name: "Jan".into(), account: "2345234".into() }, Person { name: "Kees".into(), account: "342523".into() } ]; for p in persons.iter() { // <- using .iter() here to allow multiple loops let s = p.do_explain(); println!("{}", s); } for p in persons.iter_mut() { let new_str= p.account.clone() + "_010"; p.change_account(&new_str); } change_accounts(persons.iter_mut()); change_accounts(persons.iter_mut()); change_accounts2(persons.iter_mut().map(|p| p as &mut dyn HasAccount)); change_accounts3(persons.iter_mut().map(|p| p as &mut dyn HasAccount)); for p in persons.iter() { let s = p.do_explain(); println!("{}", s); } // step 2 let mut boxed: Vec<Box<dyn HasAccount>> = vec![ Box::new(Person { name: "Piet".into(), account: "abc".into() }), Box::new(Person { name: "Klaas".into(), account: "xyz".into() }), ]; change_accounts4(boxed.iter_mut()); //boxed.iter_mut().map(|p| p.as_mut()) // step 3 let mut list: Vec<Box<dyn Entity>> = vec![ Box::new(Person { name: "Jan".into(), account: "123".into() }), Box::new(Person { name: "Kees".into(), account: "456".into() }), ]; // read explain_all(list.iter()); //.map(|x| x.as_ref()) // write let iter = list.iter_mut(); //.map(|x| x.as_mut()) change_all(iter); // read again explain_all(list.iter()); //.map(|x| x.as_ref()) let mut list2 = get_boxed_entities1(); explain_all(list2.iter()); let iter = list2.iter_mut(); change_all(iter); explain_all(list2.iter()); let mut list3: Vec<Box<dyn Entity>> = get_boxed_entities2().collect(); explain_all(list3.iter()); change_all(list3.iter_mut()); explain_all(list3.iter()); println!("Finished"); }
trait IntoBoxedA<'a>: IntoIterator<Item = &'a Box<dyn A>> {} impl<'a, T> IntoBoxedA<'a> for T where T: IntoIterator<Item = &'a Box<dyn A>> {} // 3 variants with the same behaviour: fn process1<'a, T: IntoBoxedA<'a>>(items: T) { ... } fn process1<'a, T>(items: T) where T: IntoBoxedA<'a> { ... } fn process1<'a>(items: impl IntoBoxedA<'a>) { ... } 👉 Kies impl Trait voor korte functies, en de T: Trait-vorm als je meerdere trait bounds of het concrete generieke type nodig hebt.
Per trait a concrete alias
trait IntoBoxedA<'a>: IntoIterator<Item = &'a Box<dyn A>> {} impl<'a, T> IntoBoxedA<'a> for T where T: IntoIterator<Item = &'a Box<dyn A>> {} trait IntoBoxedB<'a>: IntoIterator<Item = &'a Box<dyn B>> {} impl<'a, T> IntoBoxedB<'a> for T where T: IntoIterator<Item = &'a Box<dyn B>> {} trait IntoBoxedC<'a>: IntoIterator<Item = &'a Box<dyn C>> {} impl<'a, T> IntoBoxedC<'a> for T where T: IntoIterator<Item = &'a Box<dyn C>> {} fn process1<'a, T: IntoBoxedA<'a>>(items: T) { ... } fn process2<'a, T: IntoBoxedB<'a>>(items: T) { ... } macro_rules! define_into_boxed { ($name:ident, $trait:path) => { pub trait $name<'a>: IntoIterator<Item = &'a Box<dyn $trait>> {} impl<'a, T> $name<'a> for T where T: IntoIterator<Item = &'a Box<dyn $trait>>, {} }; } trait A { fn do_a(&self); } trait B { fn do_b(&self); } trait C { fn do_c(&self); } define_into_boxed!(IntoBoxedA, A); define_into_boxed!(IntoBoxedB, B); define_into_boxed!(IntoBoxedC, C); fn process1<'a>(items: impl IntoBoxedA<'a>) { for a in items { a.do_a(); } } fn process2<'a>(items: impl IntoBoxedB<'a>) { for b in items { b.do_b(); } }
Limetime errors
// error[E0597]: `boxed` does not live long enough // error[E0759]: `boxed` captured by a closure, but it is dropped before the closure is called let mut boxed: Vec<Box<dyn HasAccount>> = vec![ Box::new(Person { name: "Piet".into(), account: "abc".into() }), Box::new(Person { name: "Klaas".into(), account: "xyz".into() }), ]; edit_accounts(boxed.iter_mut().map(|p| p.as_mut())); // solution: collect into a Vec, this causes the iterator to be used let mut boxed: Vec<Box<dyn HasAccount>> = vec![ Box::new(Person { name: "Piet".into(), account: "abc".into() }), Box::new(Person { name: "Klaas".into(), account: "xyz".into() }), ]; let mapped: Vec<_> = boxed.iter_mut().map(|p| p.as_mut()).collect(); edit_accounts(mapped); // link original variable lifetime to iterator: fn make_iter<'a>( boxed: &'a mut [Box<dyn HasAccount>] ) -> impl Iterator<Item = &'a mut dyn HasAccount> { boxed.iter_mut().map(|b| b.as_mut()) } // Full example: trait HasAccount { fn set_account(&mut self, account: &str); } struct Person { name: String, account: String, } impl HasAccount for Person { fn set_account(&mut self, account: &str) { self.account = account.to_string(); } } fn make_iter<'a>( boxed: &'a mut [Box<dyn HasAccount>] ) -> impl Iterator<Item = &'a mut dyn HasAccount> { boxed.iter_mut().map(|b| b.as_mut()) } fn edit_accounts<'a, I>(accounts: I) where I: Iterator<Item = &'a mut dyn HasAccount>, { for a in accounts { a.set_account("updated"); } } fn main() { let mut boxed: Vec<Box<dyn HasAccount>> = vec![ Box::new(Person { name: "Piet".into(), account: "abc".into() }), Box::new(Person { name: "Klaas".into(), account: "xyz".into() }), ]; let iter = make_iter(&mut boxed); edit_accounts(iter); }
955810cookie-checkRust Mutable Iterator example