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

VectorRust

Vector Problem Overview


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)

Vector Solutions


Solution 1 - Vector

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 - Vector

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 - Vector

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKaiView Question on Stackoverflow
Solution 1 - Vectorheinrich5991View Answer on Stackoverflow
Solution 2 - VectorDK.View Answer on Stackoverflow
Solution 3 - VectorkbknappView Answer on Stackoverflow