如何创建包含大数组的结构数组?

时间:2016-10-07 19:58:51

标签: arrays struct rust

如何创建包含固定大小的大数组的结构数组?我想使用数组而不是矢量。

此代码是一个示例,但不编译

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

我正在使用Rust 1.12。

2 个答案:

答案 0 :(得分: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 :(不幸的是,我们遇到了Rust编译器的限制(适用于小于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 :(得分: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
        }
    }
}

然后,您可以从#[derive(Clone)]移除_TmoveP(刚刚离开Copy),我们终于可以找到合适的解决方案! Here是我解决方案的游乐场链接。