以下最小示例无法编译:
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:为什么修复有效?据我了解,新的可变引用应该使旧的引用无效。
为什么这是必要的?它已经是一个引用了,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创建一个新引用,其生命周期可以比原始引用短,并允许在新引用的生命周期结束后再次使用原始引用。