Simple as possible example of returning a volatile reference from your own iterator

This question is related, however it goes into more detail on the reason why the compiler is unable to infer the safe time to live when returning a volatile reference from Iterator::next

, which I think I understand.

My question is:

What are the specific steps you can take when designing your own iterator so that it can create mutable references? Ultimately, I hope for a brief, step-by-step, if possible, comment on both the implementation Iterator

and its next

that I (and anyone) can use as a clear reference when they are triggered into this situation. unsafe

examples are ok, i think they are probably needed!

NOTE. I understand that this is MutItems

usually the recommended example, however it can be difficult to follow since there is no documentation on 1. How markers work in this situation and 2. What does the macro extend iterator!

and how does it work. If you are using MutItems

as your example, please clarify these things?

Thank!

+3


source to share


1 answer


Here's a way to have a mutable iterator over a hypothetical structure Point

. Pay special attention to the big comment I put on the block unsafe

. I find it very helpful to comment on each block in a unsafe

similar way, since I only shoot in the leg if I'm wrong!



use std::mem;

#[derive(Debug)]
struct Point {
    x: u8,
    y: u8,
    z: u8,
}

impl Point {
    fn iter_mut(&mut self) -> IterMut {
        IterMut { point: self, idx: 0 }
    }
}

struct IterMut<'a> {
    point: &'a mut Point,
    idx: u8,
}

impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut u8;

    fn next(&mut self) -> Option<&'a mut u8> {
        let retval = match self.idx {
            0 => Some(&mut self.point.x),
            1 => Some(&mut self.point.y),
            2 => Some(&mut self.point.z),
            _ => None
        };

        if retval.is_some() {
            self.idx += 1;
        }

        // This is safe because...
        // (from http://stackoverflow.com/questions/25730586):
        // The Rust compiler does not know that when you ask a mutable
        // iterator for the next element, that you get a different
        // reference every time and never the same reference twice. Of
        // course, we know that such an iterator won't give you the
        // same reference twice.
        unsafe { mem::transmute(retval) }
    }
}

fn main() {
    let mut p1 = Point { x: 1, y: 2, z: 3 };

    for x in p1.iter_mut() {
        *x += 1;
    }

    println!("{:?}", p1);
}

      

+4


source







All Articles