2

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.

4

2 回答 2

5

numsin的借用doesnt_work将与变量一样持续存在l并且r存在,因为向量中的值(以及向量本身)实际上已经被借用,现在只能通过land访问r

您可以通过将letfor landr放在一个结束的作用域中来看到这种效果,因此借用也结束了。例如,此代码工作正常,但如果您尝试移动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());
}

在您的also_works示例中,您不对结果执行任何操作,因此借用立即丢失。基本上编译器可以看到您无法通过方法的结果访问向量,因此您可以通过原始向量自由访问它们。

于 2015-09-24T12:41:42.270 回答
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返回指向向量的指针?)归结为具有相同生命周期的引用。

于 2015-09-24T18:45:41.810 回答