What's the idiomatic way to append a slice to a vector?

29,893

Solution 1

There's a method that does exactly this: Vec::extend_from_slice

Example:

let s = [0u8, 1, 2];
let mut v = Vec::new();
v.extend_from_slice(&s); 

Solution 2

v.extend(s.iter().cloned());

That is effectively equivalent to using .map(|&i| i) and it does minimal copying.

The problem is that you absolutely cannot avoid copying in this case. You cannot simply move the values because a slice does not own its contents, thus it can only take a copy.

Now, that said, there are two things to consider:

  1. Rust tends to inline rather aggressively; there is enough information in this code for the compiler to just copy the values directly into the destination without any intermediate step.

  2. Closures in Rust aren't like closures in most other languages: they don't require heap allocation and can be directly inlined, thus making them no less efficient than hard-coding the behaviour directly.

Do keep in mind that the above two are dependent on optimisation: they'll generally work out for the best, but aren't guaranteed.


But having said that... what you're actually trying to do here in this specific example is append a stack-allocated array which you do own. I'm not aware of any library code that can actually take advantage of this fact (support for array values is rather weak in Rust at the moment), but theoretically, you could effectively create an into_iter() equivalent using unsafe code... but I don't recommend it, and it's probably not worth the hassle.

Solution 3

I can't speak for the full performance implications, but v + &s will work on beta, which I believe is just similar to pushing each value onto the original Vec.

Share:
29,893

Related videos on Youtube

Kai
Author by

Kai

Updated on July 09, 2022

Comments

  • Kai
    Kai almost 2 years

    I have a slice of &[u8] and I'd like to append it to a Vec<u8> with minimal copying. Here are two approaches that I know work:

    let s = [0u8, 1u8, 2u8];
    let mut v = Vec::new();
    v.extend(s.iter().map(|&i| i));
    v.extend(s.to_vec().into_iter()); // allocates an extra copy of the slice
    

    Is there a better way to do this in Rust stable? (rustc 1.0.0-beta.2)

  • Camelid
    Camelid over 3 years
    This appears to no longer work. Maybe it was removed before 1.0? (Weird though because 1.0 was released just 11 days after this answer was posted....)