是否可以在不复制数据的情况下将 Vec<&[u8]> 展平为 &[u8] ?

Kev*_*vin 2 rust

我想展平一个包含&[u8]以下内容的向量:

fn main() {
    let x: &[u8] = &b"abc"[..];
    let y: &[u8] = &b"def"[..];
    
    let z: Vec<&[u8]> = vec![x, y];
    
    println!("z: {:?}", z);
    
    let z_flat: &[u8] = z.into_iter().flatten().collect();
    
    println!("z_flat: {:?}", z_flat);
}
Run Code Online (Sandbox Code Playgroud)

我收到编译器错误:

fn main() {
    let x: &[u8] = &b"abc"[..];
    let y: &[u8] = &b"def"[..];
    
    let z: Vec<&[u8]> = vec![x, y];
    
    println!("z: {:?}", z);
    
    let z_flat: &[u8] = z.into_iter().flatten().collect();
    
    println!("z_flat: {:?}", z_flat);
}
Run Code Online (Sandbox Code Playgroud)

我还尝试了以下方法:

let z_flat: &[u8] = &z.into_iter().map(|x| x.to_vec()).flatten().collect();
Run Code Online (Sandbox Code Playgroud)

编译错误:

error[E0277]: a value of type `&[u8]` cannot be built from an iterator over elements of type `&u8`
 --> src/main.rs:9:49
  |
9 |     let z_flat: &[u8] = z.into_iter().flatten().collect();
  |                                                 ^^^^^^^ value of type `&[u8]` cannot be built from `std::iter::Iterator<Item=&u8>`
  |
  = help: the trait `FromIterator<&u8>` is not implemented for `&[u8]`
Run Code Online (Sandbox Code Playgroud)

下面工作(操场):

let z_flat: &[u8] = &z.concat();
Run Code Online (Sandbox Code Playgroud)

我无法concat在我的实际应用程序中使用,因为我在检索嵌套字节 ( xand y)时使用了另一个结构,并且该结构无法实现Copy(仅Clone),因为它包含一个Vec<u8>字段。我有类似的东西(操场):

#[derive(Clone, Debug)]
struct Foo {
    Bar: Vec<u8>,
}

impl Foo {
    fn baz(&self) -> Vec<u8> {
        self.Bar
    }
}

fn main() {
    let x = Foo { Bar: vec![8u8] };
    let y = Foo { Bar: vec![18u8] };

    let z: Vec<Foo> = vec![x, y];

    println!("z: {:?}", z);

    let z_flat = z
        .into_iter()
        .map(|x| &x.baz()[..])
        .collect::<Vec<&[u8]>>()
        .concat();

    println!("z_flat: {:?}", z_flat);
}
Run Code Online (Sandbox Code Playgroud)

编译错误:

let z_flat: &[u8] = &z.into_iter().map(|x| x.to_vec()).flatten().collect();
Run Code Online (Sandbox Code Playgroud)

She*_*ter 7

不,这是不可能的。根据定义,切片是一个连续的内存区域。你没有那个开始,所以你不能创建一个切片。

您的解决方法将所有内容复制到一个连续的内存块中,然后您可以从中获取一部分。我会这样写:

let z: Vec<&[u8]> = vec![b"abc", b"def"];
let z_alloc: Vec<u8> = z.iter().flat_map(|&x| x).copied().collect();
let z_flat: &[u8] = &z_alloc;

println!("z_flat: {:?}", z_flat);
Run Code Online (Sandbox Code Playgroud)

对于你更大的例子:

// fn baz(self) -> Vec<u8>
let z_flat: Vec<u8> = z.into_iter().flat_map(Foo::baz).collect();
Run Code Online (Sandbox Code Playgroud)
// fn baz(&self) -> &[u8]
let z_flat: Vec<u8> = z.iter().flat_map(Foo::baz).copied().collect();
Run Code Online (Sandbox Code Playgroud)

也可以看看: