Reputation: 118
I have struct Board
which contains an element rows: [[&'a mut Tile; 7];7]
I have no idea how to initialise that by a constructor in impl Board {}
block because of lifetimes, so I've tried to initialise it in the main
function.
Sadly, rows = [[&mut Tile::def(); 7]; 7]
doesn't work because Rust wants to copy the reference &mut Tile::def()
. (Where Tile::def()
is a constructor for Tile
).
Is there a way to initialise this array such that every element (i,j) is a reference to a distinct Tile
?
Currently, the only solution that works is
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, ...};
which is unsatisfactory for obvious reasons.
What I have tried was creating a function that transforms [[Tile; 7]; 7]
into the desired array, but I encountered impossibility of borrowing mutably elements of this array multiple times.
Upvotes: 1
Views: 496
Reputation: 27905
&mut
is not just "a pointer with mutation". It's a borrow. That means it can't own the Tile
, which has to belong somewhere else.
This approach
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()]];
works because each individual Tile::def()
creates a new, temporary Tile
, and the &mut
causes the temporary to be "promoted" to the stack -- see Why is it legal to borrow a temporary? for more information. But it's not the way you should fix this problem: you need something to own the Tile
s.
You could, for instance, create a Vec<Tile>
and fill rows
with references to the members of the Vec
. But that doesn't solve your initialization problem, and the real answer is easier: you want an owning pointer, so use Box<Tile>
instead of &mut Tile
.
Box
doesn't implement Copy
, but it does implement another trait that makes this job much easier: Default
.
impl Default for Tile {
fn default() -> Self {
Tile::def()
}
}
fn main() {
let mut rows: [[Box<Tile>; 7]; 7] = Default::default();
}
Depending on what Tile::def
does, you may also be able to #[derive(Default)]
instead of implementing it by hand.
There's one other option I encourage you to consider: Store all the Tile
s in a Vec
, but refer to them by indices instead of any kind of pointer. It's cheap to swap two indices, it's easy to grow the Vec
if you need to, it makes it possible to store rows
alongside its backing store without lifetime issues, and it's more cache-friendly (which may mean better performance) than storing all the Tile
s in separate allocations. But it's not necessarily ideal in all situations.
Upvotes: 1