for循环如何实现into_iter

How does for loop implement into_iter

跟进这个 question which is marked as duplicate as question

for 循环如何实现的概念 into_iter 一直困扰着我,这个 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.

根据我对此 comment 的理解,当 vec 是一个可变引用时,for i in vec.into_iter() 实际上是 for i in (&mut *vec).into_iter() 在幕后。

for i in vec怎么样,实际上是i in vec.into_iter()吗?是否有任何地方更详细地介绍了如何实现循环以及如何触发重新借用及其工作原理?

参考代码:

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

for循环被脱糖进入(这可以通过检查HIR看出):

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

具体来说,通过执行IntoIterator::into_iter(iterable)将iterable转化为迭代器。每个特征,包括 IntoIterator,都有一个隐藏的 Self 泛型参数,所以这实际上是 IntoIterator::<_>::into_iter(iterable)。从重新借用POV来看,这类似于:

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

foo::<_>(iterable)

确切的细节在 Do mutable references have move semantics? 中有解释,但一般的想法是,它没有记录。而当前的工作方式是,当编译器无法在没有推断的情况下确定某物是可变引用时,它不会被重新借用。由于_需要推理,所以不转载

接收者的工作方式不同(总是重新借入),因此 iterable.into_iter() 确实执行了重新借入。其实这个行为跟autoref and not reborrowing. See also .

有关

除了在 playground 上使用 HIR 来检查 for loop 运行 在幕后是如何进行的,Here 是关于 for loop 是如何 de-sugared.

的官方文档

从文档给出的示例中,值(一个 vec 类型)被传递到 IntoIterator::into_iter() IntoIterator::into_iter(values),这不同于作为方法调用 values.into_iter()

let values = vec![1, 2, 3, 4, 5];

for x in values {
    println!("{}", x);
}

De-sugared变成

let values = vec![1, 2, 3, 4, 5];
{
    let result = match IntoIterator::into_iter(values) {
        mut iter => loop {
            let next;
            match iter.next() {
                Some(val) => next = val,
                None => break,
            };
            let x = next;
            let () = { println!("{}", x); };
        },
    };
    result
}