#Lifetime mismatch when iterating over mutable references

1 messages · Page 1 of 1 (latest)

visual arch
#

How can I solve the lifetime issue in the code below?

#

?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)
}

}

potent coralBOT
#
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`
long raven
#

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.

visual arch
#

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.

long raven
#

How do you know it? (Not a gotcha — this matters for the best way to proceed)

visual arch
#

I'm iterating over increasingly large sequential chunks of a BitSlice from the bitvec crate.

#

The indexes won't overlap.

long raven
#

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()?

visual arch
#

I do, but then it hits me with the error above.

long raven
#

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

visual arch
#

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).

long raven
#

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:?}");
    }
}
potent coralBOT
#
     Running `target/debug/playground`

[1, 2]
[3, 4]
[5, 6]
[7, 8]
long raven
#

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)

visual arch
#

OK, let me try that.