Why collect() generate Vec<&u8>, and not Vec<u8>?

Dear Rustaceans,

I'm trying to split() a slice and then collect() them to make them back.
Here's the minimal code snippet to reproduce.

let test = b"this is very very useless string";
let x = test.split(|byte| byte.is_ascii_whitespace()).flatten().collect::<Vec<_>>();
let y = x.to_slice();

However, the type of x is Vec<&u8> so y's becomes &[&u8],
so I cannot use other existing APIs that only takes &[u8].

So some questions around here.

  • Is there a way to create &[u8]? It's primitive type so copying it wouldn't cost much. And even the assignment between u8 copies variable, and not move.
  • Is there a way to convert &[&u8] to &[u8]? It's challenging issue to me.
let x: Vec<u8> = test
    .split(|byte| byte.is_ascii_whitespace())
    .flatten()
    .map(|byte| *byte) // <<<<<<<<<<
    .collect::<Vec<_>>();
1 Like

AKA .copied().

Alternatively,

    let mut x: Vec<u8> = vec![];
    test.split(|byte| byte.is_ascii_whitespace()).for_each(|slice| {
        x.extend_from_slice(slice)
    });
    let y = x.as_slice();

Note that both of these suggestions collect a Vec<u8> and then create a local borrow to create the &[u8]. It can't last longer than the underlying Vec (x). The lifetime is limited to the local function or functions you call. Just using the Vec<u8> may suit your use case better.

(In contrast, a b"..." is a &'static [u8; _] (which can be coerced into a &'static [u8]). You can copy it around everywhere .)


There's no way to directly convert a &[&u8] to a &[u8] as the contents of a slice are contiguous in memory. So the &[u8] are a bunch of bytes in a row, but the &[&u8] could be pointing to a bunch of bytes all over the place. You have to copy them out and place them somewhere else contiguously -- e.g. into a Vec<u8>.

4 Likes