Instantiating a 2d Vec in a Struct? - rust

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
}
}
}

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();

Recursive closure inside a function [duplicate]

This is a very simple example, but how would I do something similar to:
let fact = |x: u32| {
match x {
0 => 1,
_ => x * fact(x - 1),
}
};
I know that this specific example can be easily done with iteration, but I'm wondering if it's possible to make a recursive function in Rust for more complicated things (such as traversing trees) or if I'm required to use my own stack instead.
There are a few ways to do this.
You can put closures into a struct and pass this struct to the closure. You can even define structs inline in a function:
fn main() {
struct Fact<'s> { f: &'s dyn Fn(&Fact, u32) -> u32 }
let fact = Fact {
f: &|fact, x| if x == 0 {1} else {x * (fact.f)(fact, x - 1)}
};
println!("{}", (fact.f)(&fact, 5));
}
This gets around the problem of having an infinite type (a function that takes itself as an argument) and the problem that fact isn't yet defined inside the closure itself when one writes let fact = |x| {...} and so one can't refer to it there.
Another option is to just write a recursive function as a fn item, which can also be defined inline in a function:
fn main() {
fn fact(x: u32) -> u32 { if x == 0 {1} else {x * fact(x - 1)} }
println!("{}", fact(5));
}
This works fine if you don't need to capture anything from the environment.
One more option is to use the fn item solution but explicitly pass the args/environment you want.
fn main() {
struct FactEnv { base_case: u32 }
fn fact(env: &FactEnv, x: u32) -> u32 {
if x == 0 {env.base_case} else {x * fact(env, x - 1)}
}
let env = FactEnv { base_case: 1 };
println!("{}", fact(&env, 5));
}
All of these work with Rust 1.17 and have probably worked since version 0.6. The fn's defined inside fns are no different to those defined at the top level, except they are only accessible within the fn they are defined inside.
As of Rust 1.62 (July 2022), there's still no direct way to recurse in a closure. As the other answers have pointed out, you need at least a bit of indirection, like passing the closure to itself as an argument, or moving it into a cell after creating it. These things can work, but in my opinion they're kind of gross, and they're definitely hard for Rust beginners to follow. If you want to use recursion but you have to have a closure, for example because you need something that implements FnOnce() to use with thread::spawn, then I think the cleanest approach is to use a regular fn function for the recursive part and to wrap it in a non-recursive closure that captures the environment. Here's an example:
let x = 5;
let fact = || {
fn helper(arg: u64) -> u64 {
match arg {
0 => 1,
_ => arg * helper(arg - 1),
}
}
helper(x)
};
assert_eq!(120, fact());
Here's a really ugly and verbose solution I came up with:
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
fn main() {
let weak_holder: Rc<RefCell<Weak<dyn Fn(u32) -> u32>>> =
Rc::new(RefCell::new(Weak::<fn(u32) -> u32>::new()));
let weak_holder2 = weak_holder.clone();
let fact: Rc<dyn Fn(u32) -> u32> = Rc::new(move |x| {
let fact = weak_holder2.borrow().upgrade().unwrap();
if x == 0 {
1
} else {
x * fact(x - 1)
}
});
weak_holder.replace(Rc::downgrade(&fact));
println!("{}", fact(5)); // prints "120"
println!("{}", fact(6)); // prints "720"
}
The advantages of this are that you call the function with the expected signature (no extra arguments needed), it's a closure that can capture variables (by move), it doesn't require defining any new structs, and the closure can be returned from the function or otherwise stored in a place that outlives the scope where it was created (as an Rc<Fn...>) and it still works.
Closure is just a struct with additional contexts. Therefore, you can do this to achieve recursion (suppose you want to do factorial with recursive mutable sum):
#[derive(Default)]
struct Fact {
ans: i32,
}
impl Fact {
fn call(&mut self, n: i32) -> i32 {
if n == 0 {
self.ans = 1;
return 1;
}
self.call(n - 1);
self.ans *= n;
self.ans
}
}
To use this struct, just:
let mut fact = Fact::default();
let ans = fact.call(5);

Equivalence of iterating over filter and continue condition within iteration

To keep my code somewhat legible I extracted several data structures into a separate struct:
struct S {
x: Vec<i32>,
y: HashSet<i32>,
z: Vec<i32>,
}
That lives only within one method call and it's subcalls:
fn main() {
let mut w = S { x: vec![], y: HashSet::new(), z: vec![], };
do_part_of_the_work(&mut w);
}
fn do_part_of_the_work(w: &mut S) {
// 1. Works
for (index, &item) in w.x.iter().enumerate() {
if w.y.contains(&item) {
continue;
}
w.z[index] += 1;
}
// 2. Seems equivalent to 1. but doesn't work
for (index, &item) in w.x.iter().enumerate()
.filter(|&(_, &item)| !w.y.contains(&item)) {
w.z[index] += 1;
}
// 3. Seems equivalent to 2. and doesn't work either
for (index, &item) in w.iter_not_in_y() {
w.z[index] += 1;
}
}
impl S {
fn iter_not_in_y(&self) -> impl Iterator<Item = (usize, &i32)> {
self.x.iter().enumerate().filter(move |&(_, &item)| !self.y.contains(&item))
}
}
I'm essentially trying to do what codeblock 1. does in the form of codeblock 3., with 2. as an intermediate step that doesn't work, although these seem equivalent. Had all attributes of S been local variables, it seems that all three code blocks would have worked.
Moving the codeblock inside the impl didn't get me far either:
impl S {
fn doing_it_inside_the_struct(&mut self) {
// Doing 3. inside the struct instead, doesn't work either
for (index, &item) in self.iter_not_in_y() {
self.z[index] += 1;
}
}
}
Why doesn't block 2. work? Is it not equivalent to 1.? Could this problem be avoided by choosing a different design?
Playground
The problem with version 2:
for (index, &item) in w.x.iter().enumerate()
.filter(|&(_, &item)| !w.y.contains(&item)) {
w.z[index] += 1;
}
is that the closure for filter() captures w by reference, that is, it holds a &w. This means that the whole w is borrowed as long as this closure is alive. Then when you try to mutably borrow w.z the compiler fails.
The code in the first version uses the w.y and w.z in separated borrows and w itself is never borrowed, so it works.
The solution is to write the closure to capture only the w.y and not the w. Unfortunately there is not an easy and nice syntax for that. The nicer I can write is something like:
for (index, &item) in w.x.iter().enumerate()
.filter({
let y = &w.y;
move |&(_, &item)| !y.contains(&item)
}) {
w.z[index] += 1;
}
With the let y = &w.y; you capture only the y. Now you have to mark the closure as move or else you would capture &y, and being y a temporary that would not work.
The problem with with version 3 is similar: calling a member borrows self, that is &w so you cannot modify it afterwards. But a similar workaround would not work, because what would happen if your iter_not_in_y() implementation used self.z? You could easily get to undefined behavior.

Why do I get "cannot move out of borrowed content" when using `for &item in`?

I want to get the largest item in an array where largest is define in custom logic.
Here is an i32 version that compiles
fn largest(list: &[i32]) -> i32 {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
Here is a struct version that does not compile
#[derive(Debug, Clone)]
struct Point {
x: f32,
y: f32,
}
fn largestPoint(list: &[Point]) -> Point {
// Defaulting to something
let mut myPoint: Point = Point { x: 1.0, y: 1.0 };
for &item in list.iter() {
if (item.x > myPoint.x) {
myPoint = item.clone();
}
}
myPoint
}
What does this compiler error mean?
error[E0507]: cannot move out of borrowed content
--> src/main.rs:11:9
|
11 | for &item in list.iter() {
| ^----
| ||
| |hint: to prevent move, use `ref item` or `ref mut item`
| cannot move out of borrowed content
Isn't .iter() always a reference to the original list? How can I move the item through a reference?
for &item in list.iter() {
if (item.x > myPoint.x) {
myPoint = item.clone();
}
}
The code above doesn't work because the for loop iterates over a set of references to items in the array of type &Point. When you bind this to &item you're trying to destructure the reference. This worked with the list of i32 because i32 implements Copy and so that item can just be copied but with the list of Points it has to move ownership which isn't possible.
You can fix your code by changing &item to item like this.
for item in list.iter() {
if (item.x > myPoint.x) {
myPoint = item.clone();
}
}
If that still isn't clear, consider this about this example.
for &(x, y) in [(1, 2), (2, 30)].iter() {
println!("({}, {})", x, y);
}
Also take a look at the destructuring examples at Rust by Example.

How to build a HashMap of Vectors in Rust?

I'm a Rust newbie. I'm trying to represent a directed graph's adjacency list as a HashMap of char {vertex name} to Vector of (char,int) {vertex name, cost}. I want the final HashMap to be immutable, but I'd like to build up the vector and then not need to make a copy of it to make it immutable.
My code is below. At the indicated line I get "cannot borrow immutable dereference (dereference is implicit, due to indexing) as mutable". This makes sense, as the Vec<(char,int)> in the map is not mutable. But I'm not sure how to fix it.
Is there a way to do this in Rust?
pub struct Edge {
to: char,
from: char,
weight: int
}
pub struct digraph {
_vertices: Vec<char>,
_adj_list: HashMap<char, Vec<(char,int)> >
}
impl digraph {
pub fn new(nodes: &Vec<char>, edges: &Vec<Edge> ) -> Option<digraph> {
let mut tmp_adj_list = HashMap::new();
for node in (*nodes).iter() {
tmp_adj_list.insert(*node, Vec::new());
}
for edge in (*edges).iter() {
let Edge{ to: to, from:from, weight:weight } = *edge;
if !(*nodes).contains(&to) | !(*nodes).contains(&from) {
return None;
}
tmp_adj_list[from].push((to,weight)) // *********** error here
}
Some(digraph { _vertices: (*nodes).clone(), _adj_list: tmp_adj_list })
}
}
Taking [] onto a HashMap is sugar for the (now deprecated) get(..) function, which declaration is :
fn get<'a>(&'a self, k: &K) -> &'a V
and returns a constant (&) reference. But the push(..) method of Vec expects a &mut reference, hence the error.
What you need is the get_mut(..) method of HashMap, which returns a &mut reference to the value.
Also, some minor points:
when calling a method, dereference is automatic : (*foo).bar() is exactly the same as foo.bar()
you can dereference automatically in your loop with for &edge in edges.iter() {...}
Including all this, your function becomes :
impl digraph {
pub fn new(nodes: &Vec<char>, edges: &Vec<Edge> ) -> Option<digraph> {
let mut tmp_adj_list = HashMap::new();
for &node in nodes.iter() {
tmp_adj_list.insert(node, Vec::new());
}
for &edge in edges.iter() {
let Edge{ to: to, from:from, weight:weight } = edge;
if !nodes.contains(&to) | !nodes.contains(&from) {
return None;
}
tmp_adj_list.get_mut(&from).push((to,weight))
}
Some(digraph { _vertices: nodes.clone(), _adj_list: tmp_adj_list })
}
}

Resources