2016-06-07 68 views
4

我有一些固定大小的陣列的結構:切片到固定大小的數組

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], // ... 
} 

我以字節爲單位讀出從一個文件到一個固定大小陣列和正在拷貝的那些字節到該結構的位一點點。

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

回答

4

沒有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 } 
} 

或者初始化結構,然後改變結構中的數組。

#[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方法。

+0

感謝您的詳細答案:)我走了安全的方式,因爲性能不是我的lib的這一部分所必需的 - 只需加載/解析不同的文件。 –

2

感謝@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會。

+0

@malbarbo:完成。 –