Why does Vec <T> :: split_at_mut borrow a vector for the rest of the region?

Vec<T> has two methods:

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

Both of them take a variable reference to a vector. But the amount of borrowing seems to be different, for example:

 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()); } 

The doesnt_work function doesnt_work not compile, saying that there is already mutable borrowing on nums and that it ends and the end of the function. The problem disappears if I ignore the values ​​returned from split_at_mut .

+2
source share
2 answers

Borrowing nums in doesnt_work will continue as long as the l and r variables exist, because the values ​​in the vector (and the vector itself) were literally borrowed and are now available only through l and r .

This effect can be seen by placing let for l and r in the scope, which ends so that borrowing also ends. For example, this code works fine, but if you try to move println! inside the scope (inside curly braces), then this will fail:

 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()); } 

In your also_works example also_works you are not doing anything with the result, so the loan is immediately lost. Basically, the compiler can see that you cannot access the vector through the result of the method, so that you can access them through the original vector.

+4
source

Let me answer my own question, because what I really lost is lives. This code compiles:

 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()); } 

Since the return type maybe_use makes sense, the link refers to the first argument. If we change v2 to use 'a lifetime, main will stop compiling because both vectors passed to maybe_use are considered to be borrowed. If we completely eliminate the lifetime, the compiler throws this error:

this type of function returned contains a borrowed value, but the signature does not say whether it is taken from v1 or v2

So, what surprised me at first (how does the compiler know split_at_mut returns pointers to a vector?), split_at_mut down to links that have the same lifetime.

+2
source

All Articles