2016-10-07 108 views
1

如何創建一個包含固定大小的大數組的結構數組?我想使用數組而不是向量。如何創建一個包含大型數組的結構數組?

此代碼是一個例子,但

struct _Tmove { 
    data1: usize, 
    data2: u64, 
    data3: bool, 
} 

struct _TmoveP { 
    data4: Box<[_Tmove]>, 
    data5: isize, 
} 

fn main() { 
    let mut gen_list = Box::new([ 
     _TmoveP { 
      data5: 1, 
      data4: Box::new([_Tmove { data1: 5, data2: 1, data3: true }; 300]), 
     } 
     ; 100000]); 

    assert!(gen_list[0].data4[0].data1==5); 
} 
error[E0277]: the trait bound `_Tmove: std::marker::Copy` is not satisfied 
--> src/main.rs:16:29 
     | 
    16 |    data4: Box::new([_Tmove { data1: 5, data2: 1, data3: true }; 300]), 
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    | 
    = note: the `Copy` trait is required because the repeated element will be copied 

error[E0277]: the trait bound `_TmoveP: std::marker::Copy` is not  satisfied 
--> src/main.rs:13:33 
    | 
13 |  let mut gen_list = Box::new([ 
    |        ^
    | 
    = note: the `Copy` trait is required because the repeated element will be copied 

我使用防鏽1.12不會編譯。

+2

您是否看到編譯器的錯誤?它說,「特性綁定'_TmoveP:std :: marker :: Copy'不滿意[...]注意:'Copy'特性是必需的,因爲重複的元素將被複制。這是否更清晰? – Aurora0001

+0

在兩個結構體 處添加#[派生(複製)],錯誤爲: 錯誤[E0204]:此類型的特性「複製」可能不會執行 - > src/main.rs:8:10 | 8 | #[派生(複製)] |注意:在#[derive(Copy)]的擴展中(在src/main.rs中定義)[^^^^'data4'沒有實現'Copy' src/main.rs:8:10: – gekomad

+1

X-posted here:https://www.reddit.com/r/rust/comments/56a91d/struct_of_structs_with_array/ –

回答

3

爲了受益於初始化語法:[expr; N]expr的結果需要爲Copy(因爲需要創建副本)。

#[derive(Copy, Clone)] 
struct _Tmove { 
    data1: usize, 
    data2: u64, 
    data3: bool, 
} 

#[derive(Copy, Clone)] 
struct _TmoveP { 
    data4: Box<[_Tmove]>, 
    data5: isize, 
} 

然而,在這種情況下,_TmoveP不能Copy,因爲它包含了Box這是不Copy

好吧,讓我們擺脫Box

#[derive(Copy, Clone)] 
struct _TmoveP { 
    data4: [_Tmove; 300], 
    data5: isize, 
} 

聽起來很棒?

但不幸的是,[_Tmove; 300]Clone要麼:(我們是不幸擊中鏽編譯器的限制(它適用於尺寸小於32)。

Copy是很容易的......但首先我們必須。手動執行Clone用簡單的方式是沒有樂趣,但它是很容易的:

impl Clone for _TmoveP { 
    fn clone(&self) -> _TmoveP { 
     unsafe { 
      let mut res = _TmoveP { 
       data4: std::mem::uninitialized(), 
       data5: self.data5, 
      }; 

      std::ptr::copy_nonoverlapping(
       &self.data4 as *const _Tmove, 
       std::mem::transmute(&mut res.data4), 
       300 
      ); 

      res 
     } 
    } 
} 

注:由於某種原因&mut res.data4 as *mut _不會編譯...什麼:X

然而,@Francis Gagné提醒我在評論中,有一個奇怪的招用Copy類型:

impl Clone for _TmoveP { 
    fn clone(&self) -> _TmoveP { *self } 
} 

這工作,出於某種原因,並在這些情況下派上用場。

最後,這個工程...哦,等等,在main有一個問題!

fn main() { 
    let gen_list = Box::new([ 
     _TmoveP { 
      data5: 1, 
      data4: [_Tmove { data1: 5, data2: 1, data3: true }; 300], 
     } 
     ; 100000]); 

    assert!(gen_list[0].data4[0].data1==5); 
} 

好的,here we go


什麼處理數組只適用於小於32的尺寸?

簡單地說:Rust對非類型泛型參數沒有(還?)支持。

數組在特定情況下是特殊的,但需要獨立地爲每個大小實現特徵......所以標準庫實現了32個數組的特徵,因爲它似乎是一個很好的折衷。

+1

有趣的是,我發現'[T; N]'只要'T'是'Copy',**總是**'拷貝',但它只是'克隆'高達N = 32. – Aurora0001

+0

@ Aurora0001:對!但它不是'克隆',這意味着'_TmoveP'不能是'克隆',因此它不能被'複製'。愚蠢的......愚蠢的...... :( –

+1

)如果你可以在類型上派生'Copy',你可以通過返回'* self'來簡單地實現'Clone'。 –

2

您收到此錯誤是因爲您嘗試使用默認初始化語法來初始化一個數組,但是您的結構沒有實現Copy特徵,所以這是不允許的。您可以看到here的原因,但是,簡而言之,默認初始化語法將創建一個結構副本,然後嘗試將其複製100,000次。顯然,如果你的結構沒有標記爲Copy,那麼這是不允許的,所以會引發錯誤。

通常情況下,這可以通過兩種標記您的結構來解決作爲Copy,就像這樣:

#[derive(Clone, Copy)] 
struct _Tmove { 
    data1: usize, 
    data2: u64, 
    data3: bool, 
} 

#[derive(Clone, Copy)] 
struct _TmoveP { 
    data4: Box<[_Tmove]>, 
    data5: isize, 
} 

但是,你會發現,這仍然不能編譯,因爲你沒有真正有一個數組在這裏。你實際上已經使用了該片段的類型(take a look at this similar issue)。切片不要實現Copy,所以你的代碼不能編譯,因爲_TmoveP結構只能得到Copy,如果它的所有字段都是Copy

目前還不清楚數組是否會總是有一個固定的大小。如果會,那麼您需要使用[T; N]類型,其中T是您的類型,N是元素的數量(例如[i32; 300])。如果不是,你需要一個Vec<T>

如果使用數組,則會出現另一個問題。數組實現Copy(最多32),但不是Clone,我們需要實現Clone_TmoveP,然後才能實現Copy。所以,讓我們做自己:

impl Clone for _TmoveP { 
    fn clone(&self) -> _TmoveP { 
     _TmoveP { 
      data4: self.data4, 
      data5: self.data5 
     } 
    } 
} 

您可以然後從_TmoveP(剛剛離開Copy)的#[derive(Clone)],我們終於達成有效的解決方案! Here是我解決方案的操場鏈接。

+0

生鏽1.11貨物生成一個非常大的可執行的女巫1.12生成一個小的可執行文件,但進入分段錯誤 – gekomad

+0

這很奇怪,它似乎在操場上運行良好。請注意,您正在爲每個_Tmove結構分配〜16個字節,然後存儲300個這樣的字節,另一個8字節用於「isize」,因此每個「_TmoveP」大約有4,800個字節。然後你複製那個** 100,000 **次,分配約450MB **的空間。我想知道是否會導致一些問題; LLVM可能會靜態生成數組內容,這會導致您的可執行文件的大小增大。 – Aurora0001

相關問題