Vec的可变迭代器<vec <(k,v)=“”>&gt;

时间:2017-02-24 19:31:39

标签: iterator rust

我正在尝试为类型为Vec<Vec<(K, V)>>

的向量创建一个可变迭代器

迭代器代码:

pub struct IterMut<'a, K: 'a, V: 'a> {
    iter: &'a mut Vec<Vec<(K, V)>>,
    ix: usize,
    inner_ix: usize,
}

impl<'a, K, V> Iterator for IterMut<'a, K, V> {
    type Item = (&'a K, &'a mut V);

    #[inline]
    fn next(&mut self) -> Option<(&'a K, &'a mut V)> {

        while self.iter.len() < self.ix {
            while self.iter[self.ix].len() < self.inner_ix {
                self.inner_ix += 1;
                let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
                return Some((&k, &mut v));
            }

            self.ix += 1;
        }

        return None;
    }
}

我得到的错误是:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/main.rs:16:42
   |
16 |                 let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
   |                                          ^^^^^^^^^^^^^^^^^^
   |
help: consider using an explicit lifetime parameter as shown: fn next(&'a mut self) -> Option<(&'a K, &'a mut V)>
  --> src/main.rs:11:5
   |
11 |     fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
   |     ^

显然我有生命问题,但我不知道如何告诉编译器这应该有用。

这是你应该如何实现可变迭代器还是有更好的方法?

2 个答案:

答案 0 :(得分:6)

在调试神秘的错误消息时,我发现尝试尽可能地解决问题更容易。

第一步是将表达式分解为其基本组成部分,让我们从分割索引步骤开始:

fn next(&mut self) -> Option<(&'a K, &'a mut V)> {

    while self.iter.len() < self.ix {
        while self.iter[self.ix].len() < self.inner_ix {
            self.inner_ix += 1;
            let outer: &'a mut Vec<_> = self.iter;
            let inner: &'a mut Vec<_> = &mut outer[self.ix];
            let (ref k, ref mut v) = inner[self.inner_ix];
            return Some((&k, &mut v));
        }

        self.ix += 1;
    }

    return None;
}

Index特征假设其输出的生命周期与其接收者的生命周期相关联,因此要获得'a生命周期,我们需要接收器具有&'a生命周期,并且它向上传播,导致上面的代码。

但是这里存在一个问题:let outer: &'a mut Vec<_> = self.iter;将无法编译,因为可变引用不是Copy

那么,如何从可变引用中获取可变引用(由于IndexMut获得可变引用,这必须是可能的?)

一个人使用重新借用:let outer: &'a mut Vec<_> = &mut *self.iter;

而且,哦:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> <anon>:16:45
   |
16 |                 let outer: &'a mut Vec<_> = &mut *self.iter;
   |                                             ^^^^^^^^^^^^^^^
   |

重新借用的参考号对'a无效,仅对self的(未命名)生命周期有效!

为什么生锈?为什么?

因为否则会不安全。

&mut T保证不会出现别名,但是您的方法可能会创建别名引用(如果您忘记推进索引):

#[inline]
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
    let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
    return Some((&k, &mut v));
}

即使你不这样做,也不能保证你没有rewind方法允许&#34;踩到&#34;。

TL; DR:您即将踩到地雷,而是转向Stack Overflow;)

好的,但如何实现迭代器!

当然,使用迭代器。正如Shepmaster(简要地)回答的那样,标准库中的等价物已经以FlatMap为幌子。诀窍是使用现有的迭代器来获取细节!

类似的东西:

use std::slice::IterMut;

pub struct MyIterMut<'a, K: 'a, V: 'a> {
    outer: IterMut<'a, Vec<(K, V)>>,
    inner: IterMut<'a, (K, V)>,
}

然后,只要它提供了项目,您就会从inner消费,而当它为空时,您会从outer重新填充。

impl<'a, K, V> MyIterMut<'a, K, V> {
    fn new(v: &'a mut Vec<Vec<(K, V)>>) -> MyIterMut<'a, K, V> {
        let mut outer = v.iter_mut();
        let inner = outer.next()
                         .map(|v| v.iter_mut())
                         .unwrap_or_else(|| (&mut []).iter_mut());
        MyIterMut { outer: outer, inner: inner }
    }
}

impl<'a, K, V> Iterator for MyIterMut<'a, K, V> {
    type Item = (&'a K, &'a mut V);

    #[inline]
    fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
        loop {
            match self.inner.next() {
                Some(r) => return Some((&r.0, &mut r.1)),
                None => (),
            }

            match self.outer.next() {
                Some(v) => self.inner = v.iter_mut(),
                None => return None,
            }
        }
    }
}

快速测试案例:

fn main() {
    let mut v = vec![
        vec![(1, "1"), (2, "2")],
        vec![],
        vec![(3, "3")]
    ];
    let iter = MyIterMut::new(&mut v);
    let c: Vec<_> = iter.collect();
    println!("{:?}", c);
}

打印:

[(1, "1"), (2, "2"), (3, "3")]

正如所料,所以它没有完全被打破,但我希望我不必依赖&[]'static技巧(即,std::slice::IterMut已实施{ {1}})。

答案 1 :(得分:3)

您没有提供重新实施标准Iterator::flat_map的理由,所以我只是使用它而另一个map来消除您不需要的可变性:

fn main() {
    let mut a: Vec<Vec<(u8, u8)>> = Default::default();
    let c = a.iter_mut()
        .flat_map(|x| x.iter_mut())
        .map(|&mut (ref a, ref mut b)| (a, b))
        .count();
    println!("{}", c);
}

完成后,您可以return the iterator in one of the many ways

#[derive(Debug, Default)]
struct Thing<K, V>(Vec<Vec<(K, V)>>);

impl<K, V> Thing<K, V> {
    fn iter_mut<'a>(&'a mut self) -> Box<Iterator<Item = (&'a K, &'a mut V)> + 'a> {
        Box::new(self.0
            .iter_mut()
            .flat_map(|x| x.iter_mut())
            .map(|&mut (ref a, ref mut b)| (a, b)))
    }
}

fn main() {
    let mut a = Thing::<u8, u8>::default();
    let c = a.iter_mut().count();
    println!("{}", c);
}