迭代器、守卫和两次生命周期

问题描述 投票:0回答:0

对不起下面的一个有点罗嗦的例子。 问题:我想要一个迭代器在保护下的项目(在这种情况下为 RwLockGuard)。这些项目不是参考,它们是克隆的。 好像很像那些问题:

如果不是什么新鲜事,我很抱歉。但也许这个问题还有另外一种味道,我无法理解。

所以下面有一个StructWithRwLock实现了一个Iterator。还有一个结构 ManyStructWithRwLock,它(令人惊讶地)包含结构 StructWithRwLock 的 vec。它还实现了一个迭代器。 ManyStructWithRwLock 的迭代器运行其子项的每个迭代器,并始终产生下一个最小元素。为此,使用了最小堆 (BinaryHeap) 结构。该结构不能在内部使用分配,因此它必须使用外部分配的 BinaryHeap。

最后有一个测试。在测试中创建了迭代器的两个副本。一个被丢弃在两者之间。但是出于某种原因,编译器认为对二叉堆的可变引用不会被这个 drop 实现。所以我得到这个错误

error[E0597]: `test_struct` does not live long enough
   --> src/test_example.rs:138:24
    |
138 |         let mut iter = test_struct.iter(&mut buffer_heap);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
147 |     }
    |     -
    |     |
    |     `test_struct` dropped here while still borrowed
    |     borrow might be used here, when `buffer_heap` is dropped and runs the destructor for type `BinaryHeap<StructWithRwLockIter<'_>>`
    |
    = note: values in a scope are dropped in the opposite order they are defined

为什么会这样?我需要不安全吗?如何纠正?

最小运行示例(抱歉,我试图将它最小化)

use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::sync::{Arc, RwLock, RwLockReadGuard};

type BufferHeap<'b> = BinaryHeap<StructWithRwLockIter<'b>>;

#[derive(Debug)]
pub struct StructWithRwLock {
    inner: Arc<RwLock<Vec<usize>>>
}
impl StructWithRwLock {
    pub fn iter(&self) -> StructWithRwLockIter {
        let inner = self.inner.read().unwrap();
        StructWithRwLockIter {
            inner,
            current_index: 0,
        }
    }

}
pub struct StructWithRwLockIter<'a> {
    inner: RwLockReadGuard<'a, Vec<usize>>,
    current_index: usize,
}
impl<'a> StructWithRwLockIter<'a> {
    fn peek(&self) -> Option<usize> {
        let entries = &self.inner;

        if self.current_index >= entries.len() {
            return None;
        }

        let item = entries.get(self.current_index).unwrap();
        Some(*item)
    }
}

impl<'a> Eq for StructWithRwLockIter<'a> {}

impl<'a> PartialEq<Self> for StructWithRwLockIter<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.peek().eq(&other.peek())
    }
}

impl<'a> PartialOrd<Self> for StructWithRwLockIter<'a> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.peek().partial_cmp(&other.peek())
    }
}

impl<'a> Ord for StructWithRwLockIter<'a> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.peek().cmp(&other.peek())
    }
}

impl<'a> Iterator for StructWithRwLockIter<'a> {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        let entries = &self.inner;

        if self.current_index >= entries.len() {
            return None;
        }

        let item = entries.get(self.current_index).unwrap();
        self.current_index += 1;
        Some((*item).clone())
    }
}

pub struct ManyStructWithRwLock {
    items: Vec<StructWithRwLock>
}

impl ManyStructWithRwLock {
    pub fn iter<'b, 'a:'b>(&'b self, ext_buffer: &'a mut BufferHeap<'b>) -> impl Iterator<Item = usize> +'b {
        let mut it_it = Vec::with_capacity(self.items.len());
        for item in &self.items {
            it_it.push((*item).iter());
        }
        let it_it = it_it.into_iter();

        kmerge(it_it, ext_buffer)
    }
}

/// similar to itertools::kmerge_by but using extartnal buffer
pub fn kmerge<'b,'a:'b, I>(iterable: I, ext_buffer: &'a mut BufferHeap<'b>) -> KMergeStrWLockBy<'a, 'b>
    where I: Iterator<Item=StructWithRwLockIter<'b>>,
{
    ext_buffer.clear();
    for it in iterable {
        ext_buffer.push(it);
    }
    KMergeStrWLockBy {
        heap: ext_buffer,
    }
}

pub struct KMergeStrWLockBy<'a, 'b>
{
    heap: &'a mut BufferHeap<'b>,
}

impl<'a, 'b> Iterator for KMergeStrWLockBy<'a, 'b>
{
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        let mut next = self.heap.pop()?;
        let item = next.next()?;
        self.heap.push(next);
        Some(item)
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::BinaryHeap;

    #[test]
    fn test_aggr_iterator() {
        let mut buffer_heap = BinaryHeap::with_capacity(2);
        let test_struct = ManyStructWithRwLock {
            items: vec![
                StructWithRwLock {
                    inner: Arc::new(RwLock::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
                },
                StructWithRwLock {
                    inner: Arc::new(RwLock::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
                }
            ]
        };

        let mut iter = test_struct.iter(&mut buffer_heap);
        for i in 0..10 {
            let _ = iter.next().unwrap();
        }
        drop(iter);
        let mut iter = test_struct.iter(&mut buffer_heap);
        for i in 0..10 {
            let _  = iter.next().unwrap();
        }
    }
}

rust lifetime
© www.soinside.com 2019 - 2024. All rights reserved.