初始化对struct的可变引用数组

时间:2018-12-15 01:11:16

标签: rust lifetime borrowing

我有struct Board,其中包含元素rows: [[&'a mut Tile; 7];7]

由于生命周期的原因,我不知道如何通过impl Board {}块中的构造函数来初始化它,所以我试图在main函数中对其进行初始化。

不幸的是,rows = [[&mut Tile::def(); 7]; 7]无法正常工作,因为Rust想要复制引用&mut Tile::def()。 (其中Tile::def()Tile的构造函数)。

是否可以初始化此数组,以使每个元素(i,j)都引用不同的Tile

当前,唯一可行的解​​决方案是

let mut rows = [[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()]];

let board = Board { rows : rows, ...};

由于明显的原因而不能令人满意。

我尝试过创建一个将[[Tile; 7]; 7]转换为所需数组的函数,但是我无法多次借用该数组的可变元素。

1 个答案:

答案 0 :(得分:1)

&mut不仅是“具有突变的指针”。这是借钱。这意味着它不能拥有 Tile,后者必须属于其他地方。

这种方法

let mut rows = [[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()],[&mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def(), &mut Tile::def()]];

之所以起作用,是因为每个人Tile::def()都会创建一个新的临时Tile,而&mut会导致该临时对象被“提升”到堆栈中-有关详细信息,请参见Why is it legal to borrow a temporary?更多信息。但这不是解决此问题的方法:您需要拥有 Tile s。

例如,您可以创建一个Vec<Tile>,并用对rows成员的引用来填充Vec。但这并不能解决您的初始化问题,真正的答案更容易:您想要拥有 owning 指针,因此请使用Box<Tile>而不是&mut Tile

Box并未实现Copy,但是它确实实现了另一个使这项工作更加容易的特征:Default

impl Default for Tile {
    fn default() -> Self {
        Tile::def()
    }
}

fn main() {
    let mut rows: [[Box<Tile>; 7]; 7] = Default::default();
}

根据Tile::def的功能,您也许可以#[derive(Default)]而不是手工实施。


我鼓励您考虑另一种选择:将所有Tile存储在Vec中,但是通过索引而不是任何指针来引用它们。交换两个索引很便宜,可以轻松地增长Vec,如果需要的话,可以将rows与其后备存储一起存储,而不会造成生命周期问题,并且对缓存更友好(这可能会意味着更好的性能),而不是将所有Tile存储在单独的分配中。但这并不一定在所有情况下都是理想的。