由于对 `.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对象就丢失了。


以上是由于对 `.into_iter()` 的这种隐式调用,对向量的可变引用被移动,但显式调用 `.into_iter()` 有效的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>