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