为什么Vec <t> :: split_at_mut为范围的其余部分借用了向量?

时间:2015-09-24 12:29:59

标签: rust borrow-checker

Vec<T>有两种方法:

fn push(&mut self, value: T)
fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T])

他们都对载体进行了可变引用。但借款的范围似乎有所不同,例如:

fn works() {
    let mut nums: Vec<i64> = vec![1,2,3,4];
    nums.push(5);
    println!("{}", nums.len());
}

fn doesnt_work() {
    let mut nums: Vec<i64> = vec![1,2,3,4];
    let (l,r) = nums.split_at_mut(2);
    println!("{}", nums.len());
}

fn also_works() {
    let mut nums: Vec<i64> = vec![1,2,3,4];
    let _ = nums.split_at_mut(2);
    println!("{}", nums.len());
}

doesnt_work函数没有编译,说nums已经有一个可变的借位,它结束了,函数结束了。如果我忽略从split_at_mut返回的值,问题就会消失。

2 个答案:

答案 0 :(得分:5)

numsdoesnt_work的借用将持续存在变量lr,因为向量中的值(以及向量本身)具有字面意义已被借用,现在只能通过lr访问。

您可以通过将letl的{​​{1}}放在一个范围内来结束,这样借用也会结束。例如,此代码工作正常,但如果您尝试在范围内移动r(在大括号内),则它将失败:

println!

在您的fn works() { let mut nums = vec![1,2,3,4]; { let (l, r) = nums.split_at_mut(2); //println!("{}", nums.len()); //println! will fail here } println!("{}", nums.len()); } 示例中,您不会对结果做任何事情,因此借款会立即丢失。基本上,编译器可以看到您无法通过方法的结果访问向量,因此您可以通过原始向量自由访问它们。

答案 1 :(得分:2)

让我回答我自己的问题,因为我真正缺少的是生命。此代码编译:

fn maybe_use<'a, 'b>(v1: &'a mut Vec<i64>, v2: &'b mut Vec<i64>) -> &'a mut Vec<i64> {
    v1
}

fn main() {
    let mut nums1: Vec<i64> = vec![1,2,3,4];
    let mut nums2: Vec<i64> = vec![1,2,3,4];

    let ret = maybe_use(&mut nums1, &mut nums2);

    println!("{}", nums2.len());
}

因为maybe_use的返回类型清楚地表明引用来自第一个参数。如果我们将v2更改为使用'a生命周期,则main会停止编译,因为传递给maybe_use的两个向量都被视为借用。如果我们完全省略了生命周期,编译器会发出以下错误:

  

这个函数的返回类型包含一个借来的值,但是   签名并未说明是从v1还是v2

借用的

最初让我感到惊讶的是(编译器如何知道split_at_mut返回指向向量的指针?)归结为具有相同生命周期的引用。