Mutable & Immutable Reference passing as a `self` parameter

#[derive(Debug)]
struct AttendanceInfo<'a, T, A> {
    pub primary: &'a A,
    pub reasons: &'a [T]
}

impl<'a, T, A> Iterator for AttendanceInfo<'a, T, A> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let (ele, rest) = self.reasons.split_first()?;
        self.reasons = rest;
        Some(ele)
    }
}

fn main() {
    let primary_reason = String::from("This's the main reason");
    let collections = vec![String::from("123"), String::from("555")];

    let mut attendance_info = AttendanceInfo {
        reasons: &collections,
        primary: &primary_reason
    };

    let attendance_info_ref = &mut attendance_info;
    let iter= attendance_info_ref.enumerate();

    println!("{:#?}", attendance_info);
}

I found out that the enumerate function takes self as a parameter. When I tried to pass an immutable reference, it failed immediately and resulted in the error error[E0507]: cannot move out of *attendance_info_ref which is behind a shared reference . However, it still works in the case of a mutable reference, as shown above. This is really confusing for me. Can anyone explain this behavior to me?

1 Like

that self refers to a type implements Iterator. in the standard library, there's a blanket implementation impl Iterator for &mut I where I: Iterator. so in your case, enumerate consumed the attendance_info_ref when it's type is &mut AttendanceInfo, because mut reference type &mut AttendanceInfo itself implements Iterator.

on the other hand, a immutable reference type is not a Iterator so the compiler first tries auto deref coercion, and found out that the deref-ed type AttendanceInfo does however implements Iterator, then it tries to use the deref target as the Self type of enumerate(), resulting an "cannot move out of shared reference" error.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.