Explanation about an example of borrowing


#1

Hi,

I’m trying to do the rustlings exercises to get familiar with rust, and I’m having trouble with the second execrise of move semantic.

Here is my first solution. It’s working but I don’t understand why:

// Make me compile without changing line 9! Scroll down for hints :)

pub fn main() {
    let vec0: Vec<i32> = Vec::new();
    
    // Just borrow vec0 instead of taking ownership of it
    let mut vec1 = fill_vec(&vec0);

    // This line cannot be changed
    println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0);

    vec1.push(88);

    println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);

}

# Change argument type to &Vec<i32>
fn fill_vec(vec: &Vec<i32>) -> Vec<i32> {

    let mut new_vec: Vec<i32> = Vec::new();
    
    // I thought I had to dereference vec, since its type is &Vec<i32>,
    // which reads as "reference to a Vec of i32" (if I'm not mistaken),
    // and I cannot iterate over a reference.
    //
    // for i in *vec { 
    //     new_vec.push(i);
    // }
    // 
    // But it does not work. and I don't understand why.
    // Error is "cannot move out of borrowed content"
    
    // This works though, but I just tried it randomly,
    // so not sure why. How come I have to dereference `i`?
    // Very confused here...
    for i in vec { 
        new_vec.push(*i);
    }
    
    new_vec.push(22);
    new_vec.push(44);
    new_vec.push(66);
    new_vec
}

Also, is that the correct way to copy a vector? I looked for a copy() function but did not find that.

Hope this kind of question is approriate on the forum since questions seems more general.


#2

Hi,

first things first, here’s another working solution (http://is.gd/Jpn8iP)

pub fn main() {
    let vec0 = Vec::new();

    let mut vec1 = fill_vec(&vec0);

    // Do not change the following line!
    println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0);

    vec1.push(88);

    println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);

}

fn fill_vec(vec: &Vec<i32>) -> Vec<i32> {
    let mut vec = vec.to_vec(); // this copies the vector for if T is `Clone`

    vec.push(22);
    vec.push(44);
    vec.push(66);

    vec
}

And a few explanations:


#3

Generally, when you want to manually copy something, you call clone(). Copy is when it happens automatically without your help.

for loops are unusual.

let vec0 = vec![1, 2, 3];
// This will work perfectly because the `for` loop calls `into_iter()`
// on the vec converting it into something iterable. It is moved
// in the process so `vec` is no longer accessible.
for v in vec0 { println!("{}", v); }

let vec1 = &vec![1, 2, 3];
// This is a bit different. This calls `into_iter()` on the borrowed vector
// which does something depending on the implementation but at the
// most *cannot* modify or move the borrow. `into_iter()` on a borrowed vector
// calls `iter()` on the vec which yields borrows to each element.
for v in vec1 { println!("{}", *v); }

let vec2 = &vec![1, 2, 3];
// A `for` loop always calls `into_iter()` but sometimes the fact that
// you're working with a borrowed value may not be obvious. To make
// this more clear, you dereference first and then borrow.
for v in &*vec2 { println!("{}", *v); }

// Since a proper implementation of `into_iter()` should defer to `iter`
// and `iter_mut` in the appropriate cases, association of `iter` with `&`
// and `iter_mut` with `&mut` seems appropriate.
let mut vec3 = vec![1, 2, 3];
for v in &mut vec3 { println!("mutating {} in vec3", v); *v += 1; }
for v in &vec3 { println!("borrowing {} from vec3", v); }
for v in vec3 { println!("consumed vec3 and looking at {}", v); }