Beside the direct impl on Container, you can also do this:
fn update(&mut self) {
let contents_iter = [(0, 9), (1, 8), (2, 7)];
let mut tuple = (std::mem::take(&mut self.a), std::mem::take(&mut self.b));
// let mut tuple = (&mut self.a, &mut self.b);
tuple.extend(contents_iter);
self.a = tuple.0;
self.b = tuple.1;
}
The reason to not have &mut T: Extend
may be orphan rules. (Well, incorrect reason for the magic std. So I don't know either.)
// Same API as Extend
pub trait Extend2<A> {
fn extend2<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A>;
}
// This doesn't work.
// error[E0119]: conflicting implementations of trait `Extend2<_>` for type `&mut _`
// --> src/main.rs:48:1
// |
// 41 | impl<A, E: Extend<A>> Extend2<A> for E {
// | -------------------------------------- first implementation here
// ...
// 48 | impl<A, E: Extend<A>> Extend2<A> for &mut E {
// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&mut _`
// |
// = note: downstream crates may implement trait `std::iter::Extend<_>` for type `&mut _`
impl<A, E: Extend<A>> Extend2<A> for E {
fn extend2<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A>,
{
<Vec<A> as Extend<A>>::extend(self, iter);
}
}
But we can still use the same API for reference types:
impl<A, E: Extend<A>> Extend2<A> for &mut E {
fn extend2<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A>,
{
<E as Extend<A>>::extend(self, iter);
}
}
impl<A, B, E: Default + Extend<A>, F: Default + Extend<B>> Extend2<(A, B)> for (&mut E, &mut F) {
fn extend2<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (A, B)>,
{
let e = std::mem::take(self.0);
let f = std::mem::take(self.1);
let mut ef = (e, f);
<(E, F) as Extend<(A, B)>>::extend(&mut ef, iter);
let (e, f) = ef;
*self.0 = e;
*self.1 = f;
}
}
fn update2(&mut self) {
let contents_iter = [(0, 9), (1, 8), (2, 7)];
let mut tuple = (&mut self.a, &mut self.b);
tuple.extend2(contents_iter); // works
}
Rust Playground