对不起下面的一个有点罗嗦的例子。 问题:我想要一个迭代器在保护下的项目(在这种情况下为 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();
}
}
}