error: lifetime may not live long enough
|
31 | impl<'o> Iterator for OVecIterMut<'o> {
| -- lifetime 'o defined here
...
34 | fn next(&mut self) -> Option<Self::Item> {
| - let's call the lifetime of this reference '1
...
39 | / Some(OMut {
40 | | a: unsafe { self.v.a.get_unchecked_mut(self.index - 1) },
41 | | })
| |______________^ method was supposed to return data with lifetime 'o but it is returning data with lifetime '1
I don't understand why the lifetime is reduced like this when the compiler knows self.v lives for 'o, why would it reduce the lifetime of a member of it to '1?
And a side note: when removing the mutability of the f64 borrow, the code compile.
The compiler knows that *self.v is valid for 'o, but the same is not true of borrows of*self.v. In order to ensure non-overlap of mutable references, reborrows through mutable references can't live as long as the original reference — they can only live as long as the shortest involved lifetime, which in this case is the lifetime of the &mut self via which you got access to v.
(This is specific to mutable references — immutable references are not exclusive, so they do not need this lifetime shortening.)
In general, you cannot write an Iterator over mutable references, taken from a slice, from scratch, without using unsafe code to bypass the lifetime checking [see correction below by @2e71828] while using indexing — because the compiler doesn't analyze your self.index += 1 to see that it ensures non-overlap, so if the borrow checker allowed this code, it would be unsound. (You are already using unsafe code, but only to bypass bounds checking.)
Your code looks to me to be equivalent to the usual slice iter_mut(), so for practical programming rather than a learning exercise, you should use the existing std::slice::IterMut iterator, or a wrapper around it. For applications that aren't exactly regular iteration, split_first_mut() or split_at_mut() might be useful.
No, that's UB because get_unchecked_mut takes &mut self, and that mutable borrow of self.v.a overlaps with the iterator's previously returned &muts which may still be alive. The iterator must store a raw pointer, not a reference, and avoid any operations which turn that pointer into a reference until you've narrowed it down to the specific non-overlapping reference.
You should use the built-in std::slice::IterMut instead of doing this. Unsafe code is tricky to write, and so to increase overall reliability, whenever possible, you should rely on already-written and thoroughly tested unsafe code rather than writing your own.
impl From<Vec<f64>> for OVec {
fn from(value: Vec<f64>) -> Self {
let mut v = Self {
a: Vec::with_capacity(value.len()),
};
for p in value {
v.a.push(p);
}
v
}
}