Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How does for loop implement into_iter

Follow up this question which is marked as duplicate as question here.

The concept of how for loop implement into_iter keeps haunt me down and this answer kinda creates more question to me like the terms of re-borrow, which is not mentioned in rust official document at all except in one place.

To my understanding of this comment, when vec is a mutable reference, for i in vec.into_iter() is actually for i in (&mut *vec).into_iter() behind the scene.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

How about for i in vec, is it actually i in vec.into_iter()? Is there any place that have more detail on how for loop is implemented and how re-borrowing gets triggered and how it works?

Code for reference:

fn question1_1(vec: &mut [i32]) {
    for &mut item in vec.into_iter() {
        println!("{}", item);
    }
    for &mut item in vec { // --- `vec` moved due to this implicit call to `.into_iter()`
        println!("{}", item);
    }
    vec; // Error: move occurs because `vec` has type `&mut [i32]`, which does not implement the `Copy` trait
}

pub fn main() {
    let mut s = vec![1, 2, 3];
    question1_1(&mut s);

>Solution :

for loop is desugared into (this can be seen by inspecting the HIR):

{
    let _t = match IntoIterator::into_iter(iter) {
        mut iter => loop {
            match Iterator::next(&mut iter) {
                None => break,
                Some(i) => {
                    // Body
                }
            }
        },
    };
    _t
}

Specifically, the iterable is transformed into an iterator by executing IntoIterator::into_iter(iterable). Each trait, including IntoIterator, has a hidden Self generic parameter, and so this is actually IntoIterator::<_>::into_iter(iterable). From reborrowing POV, this is similar to:

fn foo<T>(v: T) {}

foo::<_>(iterable)

The exact details are explained in Do mutable references have move semantics?, but the general idea is, it is not documented. And the current working is such that when the compiler cannot determine without inference that something is a mutable reference, it is not reborrowed. Since _ requires inference, it is not reborrowed.

The receiver works differently (always reborrowed), and thus iterable.into_iter() does perform reborrowing. In fact, this behavior is related to autoref and not reborrowing. See also What are Rust's exact auto-dereferencing rules?.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading