I want to create a struct that points to references within a large long lived array within my program. The idea is to not copy any data, but to iterate over existing memory as much as possible.
Furthermore I want to implement a trait for iterators over instances of this struct that allows me to iterate over all references that are held within all instances in the vector.
I also want this trait to be agnostic to the fact if I an iterator over borrowed data or over owned data (for convenience and since this is also the case for most standard library methods (like e.g. map) that work on iterators)
I tried to implement it like so:
use std::borrow::Borrow;
struct ArrayReferences<'r> {
refs: Vec<&'r f32>,
}
trait GetArrayIterator<'s> {
fn get_array_iterator(self) -> impl Iterator<Item = &'s f32>;
}
impl<'r, I> GetArrayIterator<'r> for I
where I: Iterator, I::Item: Borrow<ArrayReferences<'r>> + 'r
{
fn get_array_iterator(self) -> impl Iterator<Item = &'r f32>
{
self.flat_map(|array_refs| {
array_refs.borrow().refs.iter().map(|y| *y)
})
}
}
enum Options {
A,
B,
}
fn main() {
let long_lived_array = [1.0f32, 2.0, 3.0];
let v = vec![
ArrayReferences { refs: vec![&long_lived_array[0]] },
ArrayReferences { refs: vec![&long_lived_array[1]] },
ArrayReferences { refs: vec![&long_lived_array[2]] },
];
match Options::A {
Options::A => {
let iter = v.iter().get_array_iterator();
for i in iter {
println!("{}", *i);
}
},
Options::B => {
let iter = v.into_iter().get_array_iterator();
for i in iter {
println!("{}", *i);
}
},
_ => panic!(),
};
}
However I get an error within the flat map closure:
cannot return value referencing function parameter `array_refs`
returns a value referencing data owned by the current function
Related information:
* main.rs#17,13: `array_refs` is borrowed here
* main.rs#17,56: use `.collect()` to allocate the iterator: `.collect::<Vec<_>>()`
(rustc E0515)
As far as I understand this error tells me that array_refs (the closure argument) does not have a lifetime that extends beyond the closure, while I am returning an iterator that points to data owned by array_refs. However I would expect I::Item: Borrow<ArrayReferences<'r>> + 'r
to clearly convey to the compiler that array_refs has lifetime 'r
and hence tie it to the lifetime of the item in the returned iterator. However this clearly doesn't work and I can't, for the life of me, figure out how to convey the correct lifetimes to the compiler. Do I somehow have to annotate lifetimes within the closure? Do I have to create my own iterator type (similar to what map or flat_map does) to achieve the desired behaviour?
Note that I'm not interested in a solution that simply works here, this is more of an academic question do help me understand how one handles difficult situations with lifetimes and iterators like this one.