为什么 for 循环需要引用的所有权?

And*_*mer 0 rust

以下最小示例无法编译:

fn main() {
    let mut v = Vec::new();
    foo(&mut v);
}

fn foo(v_ref: &mut Vec<u8>) {
    for v in v_ref{
        println!("{}", v);
    }
    for v in v_ref{
        println!("{}", v);
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器建议将第一个 for 循环修改为此,它确实可以编译。

    for v in &mut *v_ref{
Run Code Online (Sandbox Code Playgroud)

编译器给出的推理是:

发生 move 是因为v_ref具有 type &mut Vec<u8>,但它没有实现该Copy特征

v_ref由于隐式调用而移动.into_iter()

问题1:为什么这是必要的?它已经是一个引用了,for 循环在我们完成它之后不应该返回引用吗?

问题 2:为什么修复有效?据我了解,新的可变引用应该使旧的引用无效。

Cha*_*man 5

为什么这是必要的?它已经是一个引用了,for 循环在我们完成它之后不应该返回引用吗?

for循环脱糖(大致):

{
    let iterator = IntoIterator::into_iter(iter);
    while let Some(v) = Iterator::next(&mut iterator) { ... }
}
Run Code Online (Sandbox Code Playgroud)

注意IntoIterator::into_iter(). 正如可变引用具有移动语义吗?中所解释的那样。,与共享引用相反,可变引用不是,Copy因此一旦移动它们,就无法再使用它们。通常,编译器会插入一个reborrow&mut *reference它从现有的引用创建一个新的引用,并允许仍然使用现有的引用(在不再使用新的引用之后),但这仅在已知而不推断该类型是的情况下才会发生。可变引用,这里我们需要推断来确定它。

为什么修复有效?据我了解,新的可变引用应该使旧的引用无效。

您可以将引用视为堆栈;从现有引用创建的每个引用都会将一个项目推送到堆栈上,当我们使用完它时,我们会弹出它。&mut *reference创建一个新引用,其生命周期可以比原始引用短,并允许在新引用的生命周期结束后再次使用原始引用。