Linking Rust objects to one another mutably causes borrowing problems - rust

I have a group of Rust struct instances that represent squares on a game board. Each square knows which other squares can be reached from itself.
Here is my example:
enum Direction {
North,
South,
East,
West,
}
#[derive(Debug)]
struct Square {
x: u16,
y: u16,
}
impl Square {
fn new(x: u16, y: u16) -> Self {
Square { x, y }
}
fn spawn_another_square(&self, d: Direction) -> Self {
let mut new_x = self.x;
let mut new_y = self.y;
match d {
Direction::North => new_y -= 1,
Direction::South => new_y += 1,
Direction::East => new_x += 1,
Direction::West => new_x -= 1,
}
Self::new(new_x, new_y)
}
}
The Square struct has only x and y coordinates in this example, no real data. The struct implements Debug so we can print it, and two functions: a new(), and a spawn_another_square() that returns a new square, with the coordinates of this one, but shifted north, south, east or west as desired.
If we add a main() to test this part, it works.
fn main() {
let northern_square = Square::new(10, 10);
let central_square = northern_square.spawn_another_square(Direction::South);
let western_square = central_square.spawn_another_square(Direction::West);
let eastern_square = central_square.spawn_another_square(Direction::East);
let southern_square = central_square.spawn_another_square(Direction::South);
println!("Northern square: {:?}", northern_square);
println!("Central square: {:?}", central_square);
println!("Western square: {:?}", western_square);
println!("Eastern square: {:?}", eastern_square);
println!("Southern square: {:?}", southern_square);
}
The main first creates the northern_square, using new(), at arbitrary coordinates 10, 10. This is then spawn_another_square()'d into a new central_square that is shifted Direction::South of the first. Then the central square is spawned to make the others. You get the idea.
Next step is to add information about the paths that exist between squares.
#[derive(Debug)]
struct Square {
x: u16,
y: u16,
to_the_north: Option<&Square>,
to_the_south: Option<&Square>,
to_the_east: Option<&Square>,
to_the_west: Option<&Square>,
}
impl Square {
fn new(x: u16, y: u16) -> Self {
Square {
x,
y,
to_the_north: None,
to_the_south: None,
to_the_east: None,
to_the_west: None,
}
}
fn spawn_another_square(&self, d: Direction) -> Self {
let mut new_x = self.x;
let mut new_y = self.y;
match d {
Direction::North => new_y -= 1,
Direction::South => new_y += 1,
Direction::East => new_x += 1,
Direction::West => new_x -= 1,
}
// neighbour squares will be None on new square, even if set on this square
Self::new(new_x, new_y)
}
}
Here we can see four new elements of the struct, to record which square you will find in each of the four directions. The new elements are Option<&Square>, since it is possible for there to be no square at all in some directions, and so that the Square instances can be created before the path information is known. Also, we don't want the squares to own one another, only to point to one another; it wouldn't be possible for east and west both to own central. Also, the new() function has been updated to supply the None values for the new elements.
Of course my example doesn't compile because expected named lifetime parameter, so let's fix that...
#[derive(Debug)]
struct Square<'a> {
x: u16,
y: u16,
to_the_north: Option<&'a Square<'a>>,
to_the_south: Option<&'a Square<'a>>,
to_the_east: Option<&'a Square<'a>>,
to_the_west: Option<&'a Square<'a>>,
}
impl<'a> Square<'a> {
fn new(x: u16, y: u16) -> Self {
Square {
x,
y,
to_the_north: None,
to_the_south: None,
to_the_east: None,
to_the_west: None,
}
}
fn spawn_another_square(&self, d: Direction) -> Self {
let mut new_x = self.x;
let mut new_y = self.y;
match d {
Direction::North => new_y -= 1,
Direction::South => new_y += 1,
Direction::East => new_x += 1,
Direction::West => new_x -= 1,
}
// neighbour squares will be None on new square, even if set on this square
Self::new(new_x, new_y)
}
}
It compiles, but it looks like a lot of extra <'a>s.
Now to try setting some paths, with a new function implemented on the Square struct, and an updated main(). Here's the whole thing:
enum Direction {
North,
South,
East,
West,
}
#[derive(Debug)]
struct Square<'a> {
x: u16,
y: u16,
to_the_north: Option<&'a Square<'a>>,
to_the_south: Option<&'a Square<'a>>,
to_the_east: Option<&'a Square<'a>>,
to_the_west: Option<&'a Square<'a>>,
}
impl<'a> Square<'a> {
fn new(x: u16, y: u16) -> Self {
Square {
x,
y,
to_the_north: None,
to_the_south: None,
to_the_east: None,
to_the_west: None,
}
}
fn spawn_another_square(&self, d: Direction) -> Self {
let mut new_x = self.x;
let mut new_y = self.y;
match d {
Direction::North => new_y -= 1,
Direction::South => new_y += 1,
Direction::East => new_x += 1,
Direction::West => new_x -= 1,
}
Self::new(new_x, new_y) // neighbour squares will be None on new square, even if set on this square
}
fn set_a_path(&mut self, dir: Direction, dest: &'a Square) {
match dir {
Direction::North => self.to_the_north = Some(dest),
Direction::South => self.to_the_south = Some(dest),
Direction::East => self.to_the_east = Some(dest),
Direction::West => self.to_the_west = Some(dest),
};
}
}
fn main() {
let mut northern_square = Square::new(10, 10);
let mut central_square = northern_square.spawn_another_square(Direction::South);
let mut western_square = central_square.spawn_another_square(Direction::West);
let mut eastern_square = central_square.spawn_another_square(Direction::East);
let mut southern_square = central_square.spawn_another_square(Direction::South);
northern_square.set_a_path(Direction::South, &central_square);
println!("Northern square: {:?}", northern_square);
println!("Central square: {:?}", central_square);
println!("Western square: {:?}", western_square);
println!("Eastern square: {:?}", eastern_square);
println!("Southern square: {:?}", southern_square);
}
This works, changing all the square's variables to be mutable, then setting a path with set_a_path() from the northern_square, heading South, to the central_square. This runs OK.
But adding extra paths causes my problem. One more line in main is enough.
central_square.set_a_path(Direction::East, &eastern_square);
This causes the error.
error[E0502]: cannot borrow `central_square` as mutable because it is also borrowed as immutable
--> src/main.rs:51:5
|
49 | northern_square.set_a_path(Direction::South, &central_square);
| --------------- immutable borrow occurs here
50 | // central_square.set_a_path(Direction::North, &northern_square);
51 | central_square.set_a_path(Direction::East, &eastern_square);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
54 | println!("Northern square: {:?}", northern_square);
| --------------- immutable borrow later used here
Am I completely on the wrong path? Am I going about this in an 'object oriented' way, and not a sufficiently Rusty way? Or am I close, maybe just missing the odd & ref mut * combination?
The square variables need to be mutable, to add the references to the other squares. I don't think we could create the squares with the paths already coded in, because the first square's neighbours would not have been created in time for it to receive its info.

Quick Fix
For the immediate problem your Q ends with, the fix is very simple. You just need to declare the instance you need to mutate later as mut (see comments in code below).
More Info
Sharing references between instances is fine as long as you don't need to mutate the shared-referenced instances after they've been multiply shared. Or, if you're cloning/copying instances in lieu of sharing references, you'll be okay.
If we were really implementing a game board, we could avoid the need for shared references in the fields of squares by using array/Vec indices instead. If we had a single "board" instance that owned an array or Vec that owned all the squares. Fields like to_the_north could have type usize instead of a reference. Or, some sort of handle object based internally on array position could work.
Also, implementing the board as an array-like type is a type of optimization. With the way data is cached by the processor, "locality" of contiguous data can make sequential access very quick. This would be better than implementing the board as a web of references to heap allocated instances that aren't necessarily contiguous.
If something like the above simple design won't work (array with indices/handles), and if you do intend to share MUTABLE references between these squares, then you'll need to leverage Rust's smart pointer classes/structs. With Rust's borrowing rules, in many cases, the alternatives to using the smart pointers are less than desirable. The usage model for Rust generally expects the use of the smart pointer classes where mutable shared access is needed.
The relevant smart pointer classes are:
Rc - multiple owners; reference counted.
RefCell - single owner; mutable interior.
These are typically nested as Rc<RefCell<...>>. Or if you only need ref counted multiple owner access to an instance (without interior mutability), you'll only need Rc<...>. RefCell<...> can also be used independently where it has only has one owner, and the encapsulated item needs to be modified on demand, despite the object owning the RefCell itself being immutable.
For instances of classes shared between threads, the thread-safe analogs for the above are Arc (vs Rc) and Mutex (vs RefCell).
Caveat - circular references
A Vec/array implementation using indices as handles instead of refs avoids the following issue.
If you were to have square instances holding Rc<...> references to each other, you'll likely get memory cycles. And the reference counts in cycles may not ever decrement to 0, in which case if you're creating board after board, and even if they go out of scope, there may be some lingering heap-allocated ref-counted objects building up over time.
This may not matter if your application only ever creates one single board and uses that for the duration.
Among the solutions for handling this case are use of weak pointers. You can read more on how to deal with potential memory cycles here
fn main()
{
let northern_square = Square::new(10, 10);
// Add 'mut'
let mut central_square = northern_square.spawn_another_square(Direction::South);
let western_square = central_square.spawn_another_square(Direction::West);
let eastern_square = central_square.spawn_another_square(Direction::East);
let southern_square = central_square.spawn_another_square(Direction::South);
// Now this is okay.
central_square.set_a_path(Direction::East, &eastern_square);
println!("Northern square: {:?}", northern_square);
println!("Central square: {:?}", central_square);
println!("Western square: {:?}", western_square);
println!("Eastern square: {:?}", eastern_square);
println!("Southern square: {:?}", southern_square);
}

Related

How to use rayon to update a personal struct containing an Array in Rust

CONTEXT
General overview
(Here is the github page with the minimal example of my problem, and the page of my whole project)
I'm very new to rust and I'm trying to simulate the behavior of a fluid in Rust. This is easy: computing large arrays with some functions for each timestep.
I'd like to parallelize the computations done each timestep using rayon. But the compiler doesn't want me to access a mutable struct containing an Array that I want to modify, even if I'm sure that each modification will be on different places in the array: which assure me that it's safe. (I think?).
So my question is: should I use unsafe rust in here? If so, how?
And: is it possible to make Rust understand that it's safe, or to do it properly without unsafe rust?
I saw this post which kind of resembled my problem, but couldn't find a way to use the solution for my problem.
I also tried to put unsafe {...} keywords everywhere, but the compilator still complains...
You may only need to read "Structs" subsection to understand the problem, but I will also put a "Function" subsection, in case it can be important. If you think it might not be necessary, you can skip to "Main function" subsection.
Structs
Here are my structs:
I'd like to keep them that way, as they would give me (I think) more flexibility with setters/getters, but I'm open to change the way it's implemented right now.
#[derive(Debug, PartialEq)]
struct vec2D {pub x: f64, pub y: f64}
#[derive(Debug, PartialEq)]
struct ScalarField2D {
s: Array2<f64>,
}
#[derive(Debug, PartialEq)]
struct VectorField2D {
x: ScalarField2D,
y: ScalarField2D
}
impl ScalarField2D {
// also a constructor new() but not shown for simplicity
fn get_pos(&self, x: usize, y: usize) -> f64
{return self.s[[y,x]];}
fn set_pos(&mut self, x: usize, y: usize, f: f64)
{self.s[[y,x]] = f;}
}
impl VectorField2D {
// also a constructor new() but not shown for simplicity
fn get_pos(&self, x: usize, y: usize) -> vec2D
{let vec_at_pos = vec2D {
x: self.x.get_pos(x, y),
y: self.y.get_pos(x, y)};
return vec_at_pos;}
fn set_pos(&mut self, x: usize, y: usize, vec: &vec2D)
{self.x.set_pos(x, y, vec.x);
self.y.set_pos(x, y, vec.y);}
}
Function
Here is my function: which takes a ScalarField2D struct, and computes a vector called the "gradient" at a particular position of the ScalarField2D array, and then returning this vector as a "vec2D" struct.
// computes the gradient of a scalar field at a given position
fn grad_scalar(a: &ScalarField2D,
x: i32, y: i32,
x_max: i32, y_max: i32) -> vec2D
{
let ip = ((x+1) % x_max) as usize;
// i-1 with Periodic Boundaries
let im = ((x - 1 + x_max) % x_max) as usize;
// j+1 with Periodic Boundaries
let jp = ((y+1) % y_max) as usize;
// j-1 with Periodic Boundaries
let jm = ((y - 1 + y_max) % y_max) as usize;
let (i, j) = (x as usize, y as usize);
let grad = vec2D {
x: (a.get_pos(ip, j) - a.get_pos(im, j))/(2.),
y: (a.get_pos(i, jp) - a.get_pos(i, jm))/(2.)};
return grad;
}
Main function
Here is my problem:
I try to iterate over all the possible x and y using (0..x_max).into_par_iter() (or y_max for y), compute the gradient associated with each position, and then set the value to the ScalarField2D struct using the set_pos method... Here is the main function, and the import commands, and I will show you the error message I get in the next subsection
use ndarray::prelude::*;
use rayon::prelude::*;
fn main() {
let (x_max, y_max) = (2usize, 50usize);
let (x_maxi32, y_maxi32) = (x_max as i32, y_max as i32);
let mut GD_grad_rho = VectorField2D::new(x_max, y_max);
let mut GD_rho = ScalarField2D::new(x_max, y_max);
let x_iterator = (0..x_max).into_par_iter();
x_iterator.map(|xi| {
let y_iterator = (0..y_max).into_par_iter();
y_iterator.map(|yi| {
// unsafe here?
GD_grad_rho
.set_pos(xi, yi,
&grad_scalar(&GD_rho,
xi as i32, yi as i32,
x_maxi32, y_maxi32));
});});
}
Error message
Here is the compilation error I get
error[E0596]: cannot borrow `GD_grad_rho` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:104:13
|
104 | / GD_grad_rho
105 | | .set_pos(xi, yi,
106 | | &grad_scalar(&GD_rho,
107 | | xi as i32, yi as i32,
108 | | x_maxi32, y_maxi32));
| |__________________________________________________________^ cannot borrow as mutable
error[E0596]: cannot borrow `GD_grad_rho` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:101:24
|
101 | y_iterator.map(|yi| {
| ^^^^ cannot borrow as mutable
...
104 | GD_grad_rho
| ----------- mutable borrow occurs due to use of `GD_grad_rho` in closure
For more information about this error, try `rustc --explain E0596`.
error: could not compile `minimal_example_para` due to 2 previous errors
If you want the complete thing, I created a github repo with everything in it.
Tests after susitsm answer
So I did something like this:
use ndarray::prelude::*;
use rayon::prelude::*;
fn grad_scalar(a: &Array2<f64>,
i: usize, j: usize) -> (f64, f64)
{
let array_shape = a.shape();
let imax = array_shape[0];
let jmax = array_shape[1];
// i-1 with Periodic Boundaries
let ip = ((i + 1) % imax);
// i-1 with Periodic Boundaries
let im = ((i + imax) - 1) % imax;
// j+1 with Periodic Boundaries
let jp = ((j + 1) % jmax);
// j-1 with Periodic Boundaries
let jm = ((j + jmax) - 1) % jmax;
let grad_i = (a[[ip, j]] - a[[im, j]])/2.;
let grad_j = (a[[i, jp]] - a[[i, jm]])/2.;
return (grad_i, grad_j);
}
fn main() {
let a = Array::<f64, Ix2>::ones((dim, dim));
let index_list: Vec<(_, _)> = (0..a.len())
.into_par_iter()
.map(|i| (i / a.dim().0, i % a.dim().1))
.collect();
let (r1, r2): (Vec<_>, Vec<_>) = (0..a.len())
.into_par_iter()
.map(|i| (index_list[i].0, index_list[i].1))
.map(|(i, j)| grad_scalar(&a, i, j))
.collect();
let grad_row = Array2::from_shape_vec(a.dim(), r1).unwrap();
let grad_col = Array2::from_shape_vec(a.dim(), r2).unwrap();
}
Which gives me the result I want, even though I wanted to access the values through my Structs. Which is not exactly what I want but we're getting closer
But I wonder about the efficiency for more arrays, I'll post a separate question for that
You can do something like this:
use ndarray::Array2;
use rayon::prelude::*;
fn main() {
let a: Vec<u64> = (0..20000).collect();
let a = Array2::from_shape_vec((100, 200), a).unwrap();
let stuff = |arr, i, j| (i + j, i * j);
let (x, y): (Vec<_>, Vec<_>) = (0..a.len())
.into_par_iter()
.map(|i| (i / a.dim().0, i % a.dim().1))
.map(|(i, j)| stuff(&a, i, j))
.collect();
let grad_x = Array2::from_shape_vec(a.dim(), x);
let grad_y = Array2::from_shape_vec(a.dim(), y);
let grad_vector_field = VectorField2D {
x: ScalarField2D { s: grad_x },
y: ScalarField2D { s: grad_y },
};
}
Or implement the FromParallelIterator<vec2D>
impl FromParallelIterator<vec2D> for VectorField2D {
fn from_par_iter<I>(par_iter: I) -> Self
where I: IntoParallelIterator<Item = T>
{
let (x, y): (Vec<_>, Vec<_>) = par_iter
.into_par_iter()
.map(|vec_2D| {
let vec2D { x, y } = vec_2D;
(x, y)
})
.collect();
Self {
x: ScalarField2D { s: Array2::from_shape_vec(a.dim(), x) },
y: ScalarField2D { s: Array2::from_shape_vec(a.dim(), y) },
}
}
}
This will enable using collect for your type when using parallel iterators
let vector_field: VectorField2D = (0..a.len())
.into_par_iter()
.map(|i| (index_list[i].0, index_list[i].1))
.map(|(i, j)| grad_scalar(&a, i, j))
.collect();

Two mutable borrows from vector

I am following a tutorial on breakout game written in rust and I have simple data structure representing balls on the screen:
pub struct Ball {
rect: Rect,
vel: Vec2,
}
It is stored in vector
let mut balls: Vec<Ball> = Vec::new();
However when I try to calculate ball to ball collision I encounter error:
--> src/main.rs:193:31
|
192 | for ball in balls.iter_mut() {
| ----------------
| |
| first mutable borrow occurs here
| first borrow later used here
193 | for other_ball in balls.iter_mut() {
| ^^^^^^^^^^^^^^^^ second mutable borrow occurs here
// ball collision with balls
for ball in balls.iter_mut() {
for other_ball in balls.iter_mut() {
if ball != other_ball {
resolve_collision(&mut ball.rect, &mut ball.vel, &other_ball.rect);
}
}
}
My initial approach was to use double iteration, now I know that borrow checker wont allow me to modify vector as it is considered unsafe. Is there a common pattern that I could use to solve this kind of issues?
You can achieve this using split_at_mut. It feels a bit hacky, but works OK. Here's an implementation that gets two different mutable values.
pub fn get_mut2<T>(v: &mut [T], i: usize, j: usize) -> Option<(&mut T, &mut T)> {
if i == j {
return None;
}
let (start, end) = if i < j { (i, j) } else { (j, i) };
let (first, second) = v.split_at_mut(start + 1);
Some((&mut first[start], &mut second[end - start - 1]))
}
pub fn main() {
let mut data = [0, 1, 2, 3, 4, 5, 6, 7];
let (a, b) = get_mut2(&mut data, 3, 6).unwrap();
*a += 10;
*b += 10;
eprintln!("{:?}", data); // [0, 1, 2, 13, 4, 5, 16, 7]
}
There's a working version on the playground.
You'd then need a double loop over your array lengths:
assert!(!a.is_empty());
for i in 0..a.len()-1 {
for j in i..a.len() {
let (ball_i, ball_j) = get_mut2(&mut a, i, j).unwrap();
...
}
}
Note that my loop ensures I only visit each unordered pair once.
You can use RefCell for mutability and iter() instead of iter_mut() so that compiler won't complain that the code borrows the vec twice, e.g.:
struct Ball(u32, u32);
let mut balls = vec![];
balls.push(RefCell::new(Ball(0, 0)));
// push more balls into vec
for b1 in balls.iter() {
for b2 in balls.iter() {
// change attributes of a ball
b1.borrow_mut().0 = 10;
b2.borrow_mut().1 = 20;
}
}

How can I turn a Vec of trait objects into a tree structure?

I'm trying to implement the BVH algorithm in my Rust ray tracer, but I'm having trouble with lifetimes and ownership. I have a trait Hittable that a bunch of different things implement -- Sphere, Triangle, Mesh, etc. And so I have a Vec<Box<dyn Hittable>>, which I want to turn into a tree of this struct:
pub struct BvhNode {
bounding_box: BoundingBox,
left: Box<dyn Hittable>,
right: Box<dyn Hittable>,
}
And so I have this recursive algorithm that almost works, if not for lifetime issues. My function looks like
pub fn new(objects: Vec<Box<dyn Hittable>>, start: usize, end: usize, t0: f64, t1: f64) -> Self {
let r = util::rand();
let comp = if r < 1. / 3. {
util::box_x_compare
} else if r < 2. / 3. {
util::box_y_compare
} else {
util::box_z_compare
}; // which axis to compare along (random for now)
let num_obj = end - start;
let mut left: Box<dyn Hittable>;
let mut right: Box<dyn Hittable>;
if num_obj == 1 {
left = objects[start];
right = objects[start];
} else if num_obj == 2 {
if comp(&&objects[start], &&objects[start + 1]) != Ordering::Greater {
left = objects[start];
right = objects[start + 1];
} else {
left = objects[start + 1];
right = objects[start];
}
} else {
let mut slice: Vec<&Box<dyn Hittable>> = Vec::new();
for i in start..end { // make a copy to sort
slice.push(&objects[i]);
}
slice.sort_by(comp);
let mid = start + num_obj / 2;
let l = BvhNode::new(objects, start, mid, t0, t1);
let r = BvhNode::new(objects, mid, end, t0, t1);
left = Box::new(l.clone());
right = Box::new(r.clone());
}
let left_box = left.get_bounding_box(t0, t1);
let right_box = right.get_bounding_box(t0, t1);
if left_box.is_none() || right_box.is_none() {
println!("Error: No bounding box in Bvh Node");
panic!();
}
Self { left, right, bounding_box: BoundingBox::new(Point3::origin(), Point3::origin()) }
}
First, I ran into some issues with trying to "move out of a vec", which I can't do, so I tried to implement Clone on all of the types that implement Hittable. It works for almost all of them, but my Triangle struct
pub struct Triangle <'b> {
mat: &'b Box<dyn Material>,
bounding_box: Option<BoundingBox>,
p: Vec<Point3<f64>>,
n: Vec<Vector3<f64>>,
uv: Vec<Vector2<f64>>,
}
contains reference to the material of its associated mesh, which clone doesn't like. I could make a clone of the Material itself, but it could potentially be very large and I don't want to have thousands of copies of it for each triangle in a mesh.
I feel like there has to be a better way to design my system, like get rid of references in Triangle so it can easily be copied. Once this structure is created, I won't need the Vec anymore, so being able to move the objects to out of it inside of copying them would also work, but I don't see a way to do that either.
In case it helps, the full file is on GitHub here
I was able to solve this by changing the objects Vec to &mut Vec<Box<dyn Hittable>> and then using objects.remove() instead of indexing into it. I had to change the algorithm slightly to handle the new way, but it should work.

Instantiating a 2d Vec in a Struct?

I'm having trouble instantiating a vec when using a constructor to return a new struct object. The syntax I've tried (using collect() improperly, probably) spat out a ton of compiler errors.
fn main() {
let level = Level::new();
}
struct Level {
tiles: Vec<Vec<Tile>>
}
struct Tile {
idx: i32
}
impl Level {
fn new() -> Level {
Level {
tiles: {
let mut t = Vec::new();
let mut t2 = Vec::new();
for x in range(0, 80) {
for y in range(0, 24) {
t2.push(Tile::new(x, y));
}
t.push(t2);
}
t
}
}
}
impl Tile {
fn new(x: i32, y: i32) -> Tile {
Tile { pos: Point { x: x, y: y } }
}
}
struct Point {
x: i32,
y: i32
}
I get these errors:
src/game/dungeon/level/mod.rs:47:25: 47:27 error: use of moved value: `t2`
src/game/dungeon/level/mod.rs:47 t2.push(Tile::new(x, y));
^~
src/game/dungeon/level/mod.rs:49:28: 49:30 note: `t2` moved here because it has type `collections::vec::Vec<game::dungeon::level::Tile>`, which is non-copyable
src/game/dungeon/level/mod.rs:49 t.push(t2);
^~
src/game/dungeon/level/mod.rs:49:28: 49:30 error: use of moved value: `t2`
src/game/dungeon/level/mod.rs:49 t.push(t2);
^~
src/game/dungeon/level/mod.rs:49:28: 49:30 note: `t2` moved here because it has type `collections::vec::Vec<game::dungeon::level::Tile>`, which is non-copyable
src/game/dungeon/level/mod.rs:49 t.push(t2);
^~
Yes, you're doing it incorrectly. The similar code will also be incorrect in C/C++, BTW.
let mut t = Vec::new();
let mut t2 = Vec::new();
for x in range(0, 80) {
for y in range(0, 24) {
t2.push(Tile::new());
}
t.push(t2);
}
The problem is, you're always pushing into the same t2 in the inner loop and then you're always pushing the same t2 into t. The latter is a violation of ownership semantics, so Rust compiler correctly tells you about using a moved value.
The idiomatic approach is to use iterators and it could look like this:
(0..80).map(|_| (0..24).map(|_| Tile::new()).collect()).collect()
If you need to access indices you can use map() closure arguments:
(0..80).map(|x| (0..24).map(|y| Tile::new(x, y)).collect()).collect()
The compiler should automatically deduce the desired type of collect() result.
Vladimir's answer is really nice, however I have a feeling that the functional style might hide the error here.
You are actually not far from the solution; the issue is simply that you cannot reuse the same t2 at each iteration of the outer loop. The simplest transformation, therefore, is to create t2 inside the outer loop:
impl Level {
fn new() -> Level {
Level {
tiles: {
let mut t = Vec::new();
for x in range(0, 80) {
let mut t2 = Vec::new(); // Moved!
for y in range(0, 24) {
t2.push(Tile::new(x, y));
}
t.push(t2);
}
t
}
}
}

Cannot move out of dereference of `&mut`-pointer when calling Option::unwrap

The following code doesn't compile:
struct Node {
left: Option<Box<Node>>,
right: Option<Box<Node>>,
}
impl Node {
fn new() -> Node {
Node { left: None, right: None, }
}
}
fn init_tree(root: &mut Box<Node>, n: int) {
match n {
0 => {},
_ => {
root.left = Some(box Node::new());
root.right = Some(box Node::new());
init_tree(&mut root.left.unwrap(), n - 1);
init_tree(&mut root.left.unwrap(), n - 1);
}
}
}
fn main() {
let mut root: Box<Node> = box Node::new();
init_tree(&mut root, 10);
}
The compiler error is
error: cannot move out of dereference of `&mut`-pointer
init_tree(&mut root.left.unwrap(), n - 1);
^~~~
How could I fix this error?
The Rust compiler makes no pretence to intellectual eminence or scholarship sublime; it does exactly what you tell it to, not what you meant or wanted.
In this case, when you say &mut root.left.unwrap(), what you are wanting is something that takes Option<Box<Node>> by mutable reference and gives you a &mut Box<Node>; but that’s definitely not what you actually told it to do.
What you told it to do was to take a mutable reference to the result of root.left.unwrap(); let’s look at the signature for Option.unwrap:
fn unwrap(self) -> T
So what root.left.unwrap() does is it consumes root.left, producing in its stead a Box<Node> object (or panicking if it was None). You are then left with the entire expression &mut root.left.unwrap() producing &mut Box<Node>, and consuming root.left and hence partially root. Now this you are definitely not permitted to do, as it would leave root needing to be destroyed, but you only had a mutable reference to it—it is not yours to destroy. Hence the error.
The solution is not to use unwrap but rather to write a suitable match expression yourself. Remember, .unwrap() is just match self { Some(x) => x, None => panic!(…) }, there’s nothing magic about it.
You’ll end up with something like this:
fn init_tree(root: &mut Node, n: int) {
if n != 0 {
root.left = Some(box Node::new());
root.right = Some(box Node::new());
init_tree(match root.left { Some(box ref mut x) => x, None => unreachable!() }, n - 1);
init_tree(match root.right { Some(box ref mut x) => x, None => unreachable!() }, n - 1);
}
}
(The box ref mut x part is a bit of a tangle, I’m afraid; it produces a &mut T from a Box<T>, the box meaning “unbox the value” and the ref mut meaning “and then take a mutable reference to it”. Remember that everything is back to front in patterns, with box and & meaning the opposite to what they do outside and with the whole lot reading left to right rather than right to left. Also, while you could work with &mut Box<Node> I would recommend using &mut Node there which removes one level of indirection. Incidentally if you were still using &mut Box<Node>, root.left.as_mut().unwrap() would work as well.)
This can be improved by not stuffing the thing into root immediately:
fn init_tree(root: &mut Node, n: int) {
if n != 0 {
let mut left = box Node::new();
let mut right = box Node::new();
init_tree(&mut *left, n - 1);
init_tree(&mut *right, n - 1);
root.left = Some(left);
root.right = Some(right);
}
}
That is a lot simpler to look at, &mut *left being read right to left as “dereference left (which will get you a Node from a Box<Node>) and then take a mutable reference to it (which will get you a &mut Node).

Resources