切片到固定大小的数组

时间:2016-06-07 00:47:42

标签: rust

我的结构有一些固定大小的数组:

struct PublicHeaderBlock_LAS14 {
    file_signature: [u8; 4],
    file_source_id: u16,
    global_encoding: u16,
    project_id_data_1: u32,
    project_id_data_2: u16,
    project_id_data_3: u16,
    project_id_data_4: [u8; 8],
    version_major: u8,
    version_minor: u8,
    systemIdentifier: [u8; 32], // ...
}

我正在从文件中读取字节到固定大小的数组,并将这些字节逐位复制到struct中。

fn create_header_struct_las14(&self, buff: &[u8; 373]) -> PublicHeaderBlock_LAS14 {
    PublicHeaderBlock_LAS14 {
        file_signature: [buff[0], buff[1], buff[2], buff[3]],
        file_source_id: (buff[4] | buff[5] << 7) as u16,
        global_encoding: (buff[6] | buff[7] << 7) as u16,
        project_id_data_1: (buff[8] | buff[9] << 7 | buff[10] << 7 | buff[11] << 7) as u32,
        project_id_data_2: (buff[12] | buff[13] << 7) as u16,
        project_id_data_3: (buff[14] | buff[15] << 7) as u16,
        project_id_data_4: [buff[16], buff[17], buff[18], buff[19], buff[20], buff[21], buff[22], buff[23]],
        version_major: buff[24],
        version_minor: buff[25],
        systemIdentifier: buff[26..58]
    }
}

最后一行(systemIdentifier)不起作用,因为在结构中它是[u8; 32]buff[26..58]是一个切片。我是否可以将切片返回到一个范围内的固定大小的数组,而不是按照我所说的file_signature进行操作?

2 个答案:

答案 0 :(得分:9)

没有safe方法来初始化带有切片的结构中的数组。您需要使用直接在未初始化内存上运行的unsafe块,或者使用以下两种初始化 - 然后 - 变异策略之一:

构造一个所需的数组,然后用它来初始化结构。

struct Foo {
    arr: [u8; 32],
}

fn fill(s: &[u8; 373]) -> Foo {
    let mut a: [u8; 32] = Default::default();
    a.copy_from_slice(&s[26..58]);
    Foo { arr: a }
}

或者初始化struct,然后在struct中改变数组。

#[derive(Default)]
struct Foo {
    arr: [u8; 32],
}

fn fill(s: &[u8; 373]) -> Foo {
    let mut f: Foo = Default::default();
    f.arr.copy_from_slice(&s[26..58]);
    f
}

如果你的结构有很多成员,那么第一个更干净。如果编译器无法优化中间副本,则第二个可能会快一点。但如果这是您程序的性能瓶颈,您可能会使用unsafe方法。

答案 1 :(得分:4)

感谢@malbarbo我们可以使用这个辅助函数:

use std::convert::AsMut;

fn clone_into_array<A, T>(slice: &[T]) -> A
    where A: Sized + Default + AsMut<[T]>,
          T: Clone
{
    let mut a = Default::default();
    <A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
    a
}

获得更整洁的语法:

fn main() {
    let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    let e = Example {
        a: clone_into_array(&original[0..4]),
        b: clone_into_array(&original[4..10]),
    };

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

只要T: Default + Clone

如果目标数组和传入的切片长度不同,它将panic!,因为clone_from_slice会这样做。