A strange mutable reference created in a method call affects the use of the variable outside

Viewed 40
#[derive(Clone, Copy)]
struct Data<'a> {
    i: &'a [i32],
    start: i32,
}

impl<'a> Data<'a> {
    fn new<const I: usize>(arr: &[i32; I]) -> Data {
        Data { i: arr, start: 0 }
    }
}

impl<'a> Iterator for Data<'a> {
    type Item = & 'a i32;

    fn next(&mut self) -> Option<Self::Item> {
        if (self.start as usize) < self.i.len(){
           let r = &self.i[self.start as usize];
           self.start+=1;
           Some(r)
        }else{
           None
        }
        //todo!()
    }
}

struct WrapperData<'a> {
    v: &'a Data<'a>,
}

impl<'a> IntoIterator for &'a mut WrapperData<'a> {
    type Item = &'a i32;

    type IntoIter = Data<'a>;

    fn into_iter(self) -> Self::IntoIter {
        *self.v
    }
}

fn main(){
    let arr = [1, 2, 3];
    let d = Data{start:0,i:&arr};
    let mut wr = WrapperData { v: &d };
    let ddd = wr.into_iter(); // #1
    let r = wr.v;  // #2 error
}

#1 does create a mutable borrowing from wr for the invocation of into_iter, however, after the invocation of the function, the implicitly created mutably borrowing is not used anymore, why the compiler still say #2 is an error with the diagnosis

69 |     let r = wr.v;
   |             ^^^^
   |             |
   |             use of borrowed `wr`
   |             borrow later used here

Cannot figure out the reason here.

1 Answers

You've implemented IntoIterator for &'a WrapperData<'a>, so you're telling the compiler that the lifetime of the borrow is the same as the lifetime of the wrapper. So when you call wr.into_iter() the compiler borrow wr for its whole lifetime, even if the result of into_iter is later dropped. You want to use different lifetimes here:

#[derive(Clone, Copy)]
struct Data<'a> {
    i: &'a [i32],
    start: i32,
}

impl<'a> Data<'a> {
    fn new<const I: usize>(arr: &[i32; I]) -> Data {
        Data { i: arr, start: 0 }
    }
}

impl<'a> Iterator for Data<'a> {
    type Item = & 'a i32;

    fn next(&mut self) -> Option<Self::Item> {
        if (self.start as usize) < self.i.len(){
           let r = &self.i[self.start as usize];
           self.start+=1;
           Some(r)
        }else{
           None
        }
        //todo!()
    }
}

struct WrapperData<'a> {
    v: &'a Data<'a>,
}

impl<'a, 'b> IntoIterator for &'b mut WrapperData<'a> {
    type Item = &'a i32;

    type IntoIter = Data<'a>;

    fn into_iter(self) -> Self::IntoIter {
        *self.v
    }
}

fn main(){
    let arr = [1, 2, 3];
    let d = Data{start:0,i:&arr};
    let mut wr = WrapperData { v: &d };
    let _ddd = wr.into_iter(); // #1
    let _r = wr.v;  // #2 error
}

Playground

Related