【问题标题】:Mutable iterator for Vec<Vec<(K, V)>>Vec<Vec<(K, V)>> 的可变迭代器
【发布时间】:2017-02-24 19:31:38
【问题描述】:

我正在尝试为以下类型的向量创建一个可变迭代器:Vec&lt;Vec&lt;(K, V)&gt;&gt;

迭代器代码:

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)> {
   |     ^

显然我有终身问题,但我不知道如何告诉编译器这应该可以工作。

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

【问题讨论】:

    标签: iterator rust


    【解决方案1】:

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

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

    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 生命周期,我们需要接收者具有 &amp;'a 生命周期,并且它向上传播,导致上面的代码。

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

    那么,如何从可变引用中获得可变引用(这一定是可能的,因为IndexMut 获得了可变引用)?

    一个使用重借:let outer: &amp;'a mut Vec&lt;_&gt; = &amp;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 的(未命名)生命周期内有效!

    为什么要生锈?为什么?

    因为不这样做是不安全的。

    &amp;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 方法。

    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")]
    

    正如预期的那样,它并没有完全损坏,但我希望我不必依赖 &amp;[]'static 技巧(即,std::slice::IterMut 实现了 Default)。

    【讨论】:

    • 哇!谢谢!这是一个非常好的答案!我实际上正在研究自定义哈希图。
    • outer 为空时,unwrap_or_else(...) 是空的吗?
    • @JesperAxelsson:没错。但是我刚刚更新了该位以不使用不安全代码,使用一个技巧,即对空切片的可变引用可以具有'static 生命周期。我敢打赌@MatthieuM 不知道这个。 :)
    • @FrancisGagné:我确实知道'static,但无法让代码正常工作......我错过了&amp;mut [] 周围的额外括号:(感谢编辑,现在干净多了!
    【解决方案2】:

    您没有提供重新实现标准 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);
    }
    

    【讨论】:

    • 谢谢!我想知道如何传递一个迭代器,将来会有用。
    猜你喜欢
    • 1970-01-01
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 2016-02-06
    • 1970-01-01
    相关资源
    最近更新 更多