#Lifetime mismatch when iterating over mutable references
1 messages · Page 1 of 1 (latest)
?eval ```rust
struct IterMut<'a> {
data: &'a mut (),
}
impl<'a> Iterator for IterMut<'a> {
type Item = &'a mut ();
fn next(&mut self) -> Option<Self::Item> {
Some(self.data)
}
}
error: lifetime may not live long enough
--> src/main.rs:10:9
|
6 | impl<'a> Iterator for IterMut<'a> {
| -- lifetime `'a` defined here
...
9 | fn next(&mut self) -> Option<Self::Item> {
| - let's call the lifetime of this reference `'1`
10 | Some(self.data)
| ^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
In general, you can't write an iterator over mutable references "from scratch" without unsafe code.
The one you've written is in fact unsound (or would be if it was less trivial) if it were allowed to compile:
if I run {some IterMut}.take(2).collect() then I now have 2 mutable references to the same data, which is UB by definition.
In the actual case, I know the results are unique mutable references.
They are smart pointers, too, so I don't know if pointers will work.
How do you know it? (Not a gotcha — this matters for the best way to proceed)
I'm iterating over increasingly large sequential chunks of a BitSlice from the bitvec crate.
The indexes won't overlap.
Okay, so if you are starting with indexes then you cannot do this without unsafe code. The unsafe code is necessary to tell the compiler "I promise I'm doing my arithmetic correctly."
But maybe you can use split_at_mut()?
I do, but then it hits me with the error above.
For regular slices, and hopefully bitslices too. that's a way to get multiple mutable refs without
hm
the reason you have the error you do is because your returning is trying to reborrow the mutable reference
reborrows happen in situations that would otherwise move the mutable ref
so you can understand the error as essentially "you tried to move the &'a mut () out of self" in disguise
Is there a way to use unsafe without pointers to overcome that?
(I think there might not be pointers for bitslices, since the addresses are essentially by bit).
tinkering with an example …
?play
struct IterMut<'a> {
data: &'a mut [u32],
count: usize,
}
impl<'a> Iterator for IterMut<'a> {
type Item = &'a mut [u32];
fn next(&mut self) -> Option<Self::Item> {
if self.count <= self.data.len() {
let data = std::mem::replace(&mut self.data, &mut [/* dummy */]);
let (head, tail) = data.split_at_mut(self.count);
self.data = tail;
Some(head)
} else {
None
}
}
}
fn main() {
let mut data = [1, 2, 3, 4, 5, 6, 7, 8];
for chunk in (IterMut { data: &mut data, count: 2 }) {
println!("{chunk:?}");
}
}
Running `target/debug/playground`
[1, 2]
[3, 4]
[5, 6]
[7, 8]
this ought to work modulo the bitslice-specific Alias thing which I don't know about
the most tricky bit here is that mem::replace is needed to enable moving the mutable ref out of self so that it can be split
the key thing here is that you must not reborrow because reborrowing creates a shorter-lived reference
and reborrows happen when you do something that would be a move (ish)
so treat the &'a mut [whatever] as if it were an ordinary not-Copy value — you have to swap it with something
(you could also store an Option inside the iterator to allow a simple .take() but that creates additional complications)
OK, let me try that.