foehn
foehn

Reputation: 467

How to push a variable's value into a vector but keep the variable alive?

I got a question about how to move a variable into a vector but without destroying this variable because it has to be reused in a loop. Below shows what I mean:

type Letter = char;
type LetterSet = Vec<Letter>;

fn main() {
    let mut v = Vec::<LetterSet>::new();
    let mut letterset: LetterSet = LetterSet::new(); 

    for i in 0..5 {
        let a = (48 + i as u8) as char;
        letterset.push(a);
        if i % 2 == 1 {
            let b = (65 + i as u8) as char;
            letterset.push(b); 
        } else {
            let c = (97 + i as u8) as char;
            letterset.push(c);
        }
        v.push(letterset.clone());
        letterset.clear();
    }

    for letterset in v {
        for letter in letterset {
            print!("{} ", letter);
        }
        println!("");
    } 
}

The code above runs. However, I want to avoid clone in

        v.push(letterset.clone());
        letterset.clear();

since letterset will be cleared anyways. Rather, I want to move its contents into v but keep it alive, because letterset has to be for the next iteration.

I tried to remove .clone() but obviously this results in a 'borrow after move' error. I wonder how to do it, thanks.

Upvotes: 0

Views: 2371

Answers (2)

orlp
orlp

Reputation: 117641

You can simply move the letterset initialization into the inner loop:

for i in 0..5 {
    let mut letterset: LetterSet = LetterSet::new(); 
    let a = (48 + i as u8) as char;
    letterset.push(a);
    if i % 2 == 1 {
        let b = (65 + i as u8) as char;
        letterset.push(b); 
    } else {
        let c = (97 + i as u8) as char;
        letterset.push(c);
    }
    v.push(letterset);
}

Or eliminate it entirely:

for i in 0..5 {
    let a = (48 + i as u8) as char;
    let b = (65 + i as u8) as char;
    let c = (97 + i as u8) as char;
    v.push(vec![a, if i % 2 == 1 { b } else { c }]);
}

Upvotes: 1

Mathieu Rene
Mathieu Rene

Reputation: 994

Why not create a new LetterSet at every iteration? Moving a Vec is only moving references to the heap, it's pretty cheap.

If you really want to re-use the same var you can use std::mem::take which will return the Vec and replace the original variable by its default (an empty vec) - this has the same behaviour since you're making a new Vec every time.

v.push(std::mem::take(&mut letterset));

You can also skip .clear() since it'll be already empty.

Upvotes: 1

Related Questions