由于对 `.into_iter()` 的这种隐式调用,对向量的可变引用被移动,但显式调用 `.into_iter()` 有效
这将失败:
fn ppv(arr: &mut Vec<i32>) {
if arr.len() <= 0 {
return;
}
let mut pp: i32 = 0;
for &mut val in arr {
if val == pp {
pp = val;
}
}
println!("arr is {:?}", &arr);
}
但这会过去:
fn ppv(arr: &mut Vec<i32>) {
if arr.len() <= 0{
return;
}
let mut pp: i32 = 0;
for &mut val in arr.into_iter() {
if val == pp {
pp = val;
}
}
println!("arr is {:?}", &arr);
}
当我编译第一个时,它失败了:
fn ppv(arr: &mut Vec<i32>) {
if arr.len() <= 0 {
return;
}
let mut pp: i32 = 0;
for &mut val in arr {
if val == pp {
pp = val;
}
}
println!("arr is {:?}", &arr);
}
这是为什么?是不是有不同的解释?第一种情况将隐式调用into_iter(),它失败了,当我调用时into_iter(),它通过了。发生了什么?
回答
我相信区别在于reborrow,在后一种情况下执行,而不是前者。
可变引用通常不是Copy. 这是设计使然,因为复制可变引用将允许可变别名。但是,问题是这是如何工作的:
fn foo(v: &mut Vec<i32>) {
v.push(1); // equivalent to Vec::push(v, 1)
v.push(2); // equivalent to Vec::push(v, 2)
}
如果对push()receive的第一次调用v不是Copy,则第二次调用push()应该无法通过“使用移动值”进行编译。然而它可以编译,脱糖版本也是如此。
它编译的原因是编译器自动执行重新借用,替换v为&mut *v. 换句话说。这个转换是在接收者 ( self) 和函数参数上完成的:
// v is &mut Vec<i32>
v.push(1); // treated as (&mut *v).push(1)
Vec::push(v, 2); // treated as Vec::push(&mut *v, 2)
重新借用的形式可以编译,因为它允许基于现有的可变引用(例如通过&mut r.some_fieldwhere ris &mut SomeStruct)创建临时可变引用,只要临时引用的寿命比原始引用短,并且您在临时一个是活的。
您通常会注意到,只有在失败的极少数情况下才会重新借款。这个答案描述了 serde 的这种情况,其中由于使用泛型而重新借用失败。
回到最初的例子,你的for循环是重新借用失败的另一个例子。给定一个可变的引用arr,之间的区别for &mut val in arr,并for &mut val in arr.into_iter()是显式调用到into_iter()被视为(&mut *arr).into_iter()从而允许继续使用的arr循环之后。裸体for不这样做,arr对象就丢失了。
THE END
二维码