'How to avoid "move occurs because `v` has type `Vec<char>`, which does not implement the `Copy` trait" within loop

It appears that a prohibited borrow is occurring here but I am not seeing a way around it to do what I'd need to do. It looks like the problem occurs when after setting the mut value within the loop I then try to save it into another Vec. Is there a clean way to get around this or a way to show this move to the compiler so I won't get the error? I'll include the error below the code snippet:

let mut result: Vec<String> = vec![];
let mut v = vec![];
for idx in 0..board.spaces.len() {
    let c: char = match board.count_at(idx as u32) {
        0 => ' ',
        1 => '1',
        2 => '2',
        3 => '3',
        4 => '4',
        5 => '5',
        6 => '6',
        7 => '7',
        8 => '8',
        _ => 'F'
    };

    v.push(c);

    if idx as u32 + 1 % board.width == 0 {
        result.push(v.into_iter().collect());
        v.clear();
    }
}

Error:

error[E0382]: borrow of moved value: `v`
   --> src/lib.rs:41:9
    |
26  |     let mut v = vec![];
    |         ----- move occurs because `v` has type `Vec<char>`, which does not implement the `Copy` trait
...
41  |         v.push(c);
    |         ^^^^^^^^^ value borrowed here after move
...
44  |             result.push(v.into_iter().collect());
    |                           ----------- `v` moved due to this method call, in previous iteration of loop
    |
note: this function takes ownership of the receiver `self`, which moves `v`


Solution 1:[1]

The reason your code doesn't work is because .into_iter() consumes the Vec and it can no longer be used later in the program. You can fix that by doing:

result.push(v.iter().clone().collect());

but I would instead hold the temporary data in a String and push a clone of it into the Vec:

let mut result: Vec<String> = vec![];
let mut s = String::new();
for idx in 0..board.spaces.len() {
    let c: char = match board.count_at(idx as u32) {
        0 => ' ',
        1 => '1',
        2 => '2',
        3 => '3',
        4 => '4',
        5 => '5',
        6 => '6',
        7 => '7',
        8 => '8',
        _ => 'F'
    };

    s.push(c);

    if idx as u32 + 1 % board.width == 0 {
        result.push(s.clone());
        s.clear();
    }
}

Solution 2:[2]

You can use Vec::append() for "empty myself, pass all elements to a new vector":

let mut result: Vec<String> = vec![];
let mut v = vec![];
for idx in 0..board.spaces.len() {
    let c: char = match board.count_at(idx as u32) {
        0 => ' ',
        1 => '1',
        2 => '2',
        3 => '3',
        4 => '4',
        5 => '5',
        6 => '6',
        7 => '7',
        8 => '8',
        _ => 'F'
    };

    v.push(c);

    if idx as u32 + 1 % board.width == 0 {
        let mut s = Vec::new();
        s.append(&mut v); // Pass all elements from `v` to `s`.
        result.push(s.into_iter().collect());
    }
}

You can also use String directly and push characters with push(), but since String doesn't include an append method you can use std::mem::take():

let mut result: Vec<String> = vec![];
let mut v = String::new();
for idx in 0..board.spaces.len() {
    let c: char = match board.count_at(idx as u32) {
        0 => ' ',
        1 => '1',
        2 => '2',
        3 => '3',
        4 => '4',
        5 => '5',
        6 => '6',
        7 => '7',
        8 => '8',
        _ => 'F'
    };

    v.push(c);

    if idx as u32 + 1 % board.width == 0 {
        result.push(std::mem::take(&mut v));
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dogbert
Solution 2 Chayim Friedman