I'm trying to implement a general function join()
that can work on any iterator of iterators. I have a problem with the borrow checker in a match
expression inside the next()
method implementation. Here is a simplified version of my code:
pub struct Join<I>
where
I: Iterator,
I::Item: IntoIterator,
{
outer_iter: I,
inner_iter: Option<<I::Item as IntoIterator>::IntoIter>,
}
impl<I> Join<I>
where
I: Iterator,
I::Item: IntoIterator,
{
pub fn new(mut iter: I) -> Join<I> {
let inner_iter = iter.next().map(|it| it.into_iter());
Join {
outer_iter: iter,
inner_iter,
}
}
}
impl<I> Iterator for Join<I>
where
I: Iterator,
I::Item: IntoIterator,
{
type Item = <I::Item as IntoIterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
loop {
match &mut self.inner_iter {
Some(ref mut it) => match it.next() {
Some(x) => {
return Some(x);
}
None => {
self.inner_iter = self.outer_iter.next().map(|it| it.into_iter());
}
},
None => {
return None;
}
}
}
}
}
pub trait MyItertools: Iterator {
fn join(self) -> Join<Self>
where
Self: Sized,
Self::Item: IntoIterator,
{
Join::new(self)
}
}
impl<I> MyItertools for I where I: Iterator {}
#[cfg(test)]
mod test {
use super::MyItertools;
#[test]
fn it_works() {
let input = [[1], [2]];
let expected = [&1, &2];
assert_eq!(input.iter().join().collect::<Vec<_>>(), expected);
}
}
Text of error:
error[E0506]: cannot assign to `self.inner_iter` because it is borrowed
--> src/main.rs:39:25
|
33 | match &mut self.inner_iter {
| --------------- borrow of `self.inner_iter` occurs here
...
39 | self.inner_iter = self.outer_iter.next().map(|it| it.into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.inner_iter` occurs here
I understand why the borrow checker complains about my code, but I did not find a good solution, only an ugly workaround:
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.inner_iter.take() {
Some(mut it) => {
match it.next() {
Some(x) => { self.inner_iter = Some(it); return Some(x); }
None => { self.inner_iter = self.outer_iter.next().map(|it| it.into_iter()); }
}
}
None => { return None; }
}
}
}
I imagine that situations like this occur regularly; how can I rewrite my code to deal with them or avoid them?