Unable to borrow a Vec inside of a closure - rust

I have a vector of Units. I'm trying to construct a Vec<Vec<Unit>> variable, called world. In the process of creating tiles, I need to know what tiles are adjacent that it knows of.
I have a function that returns a vector of points ((usize, usize)) that are adjacent to another point, and I'm converting that to an iterator, mapping over it, and getting the actual unit associated with that position in world if it's there, or the current line which has not yet been committed to world.
I need to access that line inside the closure that map takes, but I also need to access it later.
fn adjacent((x, y): (usize, usize)) -> Vec<(usize, usize)> {
vec![
(x+1, y),
(x-1, y),
(x, y+1),
(x, y-1),
]
}
struct Unit {
pub tiles: Vec<Tile>,
}
#[derive(Copy, Clone)]
enum Tile {
Floor, Wall, Empty
}
fn main() {
let heightmap = vec![
vec![3, 3, 3, 3, 3, 3],
vec![3, 1, 1, 1, 1, 3],
vec![3, 1, 1, 1, 1, 3],
vec![3, 1, 1, 1, 1, 3],
vec![3, 1, 1, 1, 1, 3],
vec![3, 1, 1, 1, 1, 3],
vec![3, 3, 3, 3, 3, 3],
];
let (sx, sy) = (5, 5);
let mut world: Vec<Vec<Unit>> = vec![];
for y in 0..sy {
let mut line: Vec<Unit> = vec![];
for x in 0..sx {
let mut tiles: Vec<Tile> = vec![];
let height = heightmap[y][x];
let adj = adjacent((x, y))
.iter()
.map(|&(x, y)| {
let list = if y > world.len() {
vec![]
} else if y == world.len() {
line
} else {
world[y]
};
if x >= list.len() {
Tile::Empty
} else {
if height as usize >= list[x].tiles.len() {
Tile::Empty
} else {
list[x].tiles[height as usize]
}
}
})
.collect::<Vec<_>>();
for z in 0..(height as isize - 1) {
tiles.push(Tile::Wall);
}
line.push(Unit {
tiles: tiles,
});
}
world.push(line);
}
}
Here is the Rust Playground.
I would have rather used unwrap_or in combination with get and so on but that leads to other errors with temporary values, and that would be more complicated anyway, so the above code, while probably not optimal, is as simple as I can get it while still duplicating the error. I've found out that a lot of the errors I get with Rust is because what I'm doing isn't the best way to go about it, so if there is a more idiomatic way, I would certainly like to know.
I've tried to make Unit cloneable (deriving Clone and Copy) but Rust won't let me for some reason, even though all it is made up of is vectors which are cloneable if their members are.

Here's a smaller example of your problem:
fn main() {
let mut line = vec![1];
let something_to_iterate_over = vec![true, false, true];
for _ in 0..2 {
let _dummy: Vec<_> = something_to_iterate_over
.iter()
.map(|&value| {
let maybe_moved_line = if value { vec![] } else { line };
() // Don't care about the return value
})
.collect();
line.push(2);
}
}
The first part of the error message is:
error[E0382]: capture of moved value: `line`
--> src/main.rs:9:67
|
8 | .map(|&value| {
| -------- value moved (into closure) here
9 | let maybe_moved_line = if value { vec![] } else { line };
| ^^^^ value captured here after move
|
= note: move occurs because `line` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `line`
--> src/main.rs:14:9
|
8 | .map(|&value| {
| -------- value moved (into closure) here
...
14 | line.push(2);
| ^^^^ value used here after move
|
= note: move occurs because `line` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
As the error message is attempting to convey, the code no longer has ownership of the variable line after the map call because the ownership has been transferred to the closure.
The code is attempting to give a single Vec to someone else while keeping it for itself, and that's simply not how ownership works. I can't give you my car and then continue to drive it everyday — it's not mine to drive!
The smallest amount of change to get your code to compile is to stop trying to give away the one and only line, but instead to clone it as needed:
Add #[derive(Clone)] to Unit
Clone line and world[y] inside the closure: line.clone(), world[y].clone()
After doing this, the code never gives up ownership of line so it can be cloned whenever needed.

Related

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 to get array of Vec<i64> from a array of JoinHandle<Vec<i64>>?

I'm trying to learn multithreads but I'm stuck on this situation:
use std::thread;
fn main() {
let numbers = vec![15i64, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
let total_threads = 4;
let mut slices = Vec::with_capacity(total_threads);
let size_slice = numbers.len() / total_threads;
for k in 0..total_threads {
let slice = numbers[size_slice * k..size_slice * (k + 1)].to_vec();
slices.push(slice);
}
let mut handles = Vec::new();
for slice in slices.iter() {
let mut new_slice = slice.to_vec();
new_slice.push(5);
let handle: thread::JoinHandle<Vec<i64>> = thread::spawn(|| {
// Example without sorting, because the problem is the same
new_slice
});
handles.push(handle);
}
let mut new_numbers = Vec::new();
for handle in handles.iter() {
new_numbers.push(handle.join().unwrap());
}
println!("{:?}", new_numbers);
}
Which is giving me the error:
error[E0507]: cannot move out of `*handle` which is behind a shared reference
--> src/main.rs:30:26
|
30 | new_numbers.push(handle.join().unwrap());
| ^^^^^^ move occurs because `*handle` has type `JoinHandle<Vec<i64>>`, which does not implement the `Copy` trait
I would like to ask how may I proceed here, or if there is a right way to do this.
The object of the program is to do merge sort simultaneously in various vectors.

How can I group consecutive integers in a vector in Rust?

I have a Vec<i64> and I want to know all the groups of integers that are consecutive. As an example:
let v = vec![1, 2, 3, 5, 6, 7, 9, 10];
I'm expecting something like this or similar:
[[1, 2, 3], [5, 6, 7], [9, 10]];
The view (vector of vectors or maybe tuples or something else) really doesn't matter, but I should get several grouped lists with continuous numbers.
At the first look, it seems like I'll need to use itertools and the group_by function, but I have no idea how...
You can indeed use group_by for this, but you might not really want to. Here's what I would probably write instead:
fn consecutive_slices(data: &[i64]) -> Vec<&[i64]> {
let mut slice_start = 0;
let mut result = Vec::new();
for i in 1..data.len() {
if data[i - 1] + 1 != data[i] {
result.push(&data[slice_start..i]);
slice_start = i;
}
}
if data.len() > 0 {
result.push(&data[slice_start..]);
}
result
}
This is similar in principle to eXodiquas' answer, but instead of accumulating a Vec<Vec<i64>>, I use the indices to accumulate a Vec of slice references that refer to the original data. (This question explains why I made consecutive_slices take &[T].)
It's also possible to do the same thing without allocating a Vec, by returning an iterator; however, I like the above version better. Here's the zero-allocation version I came up with:
fn consecutive_slices(data: &[i64]) -> impl Iterator<Item = &[i64]> {
let mut slice_start = 0;
(1..=data.len()).flat_map(move |i| {
if i == data.len() || data[i - 1] + 1 != data[i] {
let begin = slice_start;
slice_start = i;
Some(&data[begin..i])
} else {
None
}
})
}
It's not as readable as a for loop, but it doesn't need to allocate a Vec for the return value, so this version is more flexible.
Here's a "more functional" version using group_by:
use itertools::Itertools;
fn consecutive_slices(data: &[i64]) -> Vec<Vec<i64>> {
(&(0..data.len()).group_by(|&i| data[i] as usize - i))
.into_iter()
.map(|(_, group)| group.map(|i| data[i]).collect())
.collect()
}
The idea is to make a key function for group_by that takes the difference between each element and its index in the slice. Consecutive elements will have the same key because indices increase by 1 each time. One reason I don't like this version is that it's quite difficult to get slices of the original data structure; you almost have to create a Vec<Vec<i64>> (hence the two collects). The other reason is that I find it harder to read.
However, when I first wrote my preferred version (the first one, with the for loop), it had a bug (now fixed), while the other two versions were correct from the start. So there may be merit to writing denser code with functional abstractions, even if there is some hit to readability and/or performance.
let v = vec![1, 2, 3, 5, 6, 7, 9, 10];
let mut res = Vec::new();
let mut prev = v[0];
let mut sub_v = Vec::new();
sub_v.push(prev);
for i in 1..v.len() {
if v[i] == prev + 1 {
sub_v.push(v[i]);
prev = v[i];
} else {
res.push(sub_v.clone());
sub_v.clear();
sub_v.push(v[i]);
prev = v[i];
}
}
res.push(sub_v);
This should solve your problem.
Iterating over the given vector, checking if the current i64 (in my case i32) is +1 to the previous i64, if so push it into a vector (sub_v). After the series breaks, push the sub_v into the result vector. Repeat.
But I guess you wanted something functional?
Another possible solution, that uses std only, could be:
fn consecutive_slices(v: &[i64]) -> Vec<Vec<i64>> {
let t: Vec<Vec<i64>> = v
.into_iter()
.chain([*v.last().unwrap_or(&-1)].iter())
.scan(Vec::new(), |s, &e| {
match s.last() {
None => { s.push(e); Some((false, Vec::new())) },
Some(&p) if p == e - 1 => { s.push(e); Some((false, Vec::new()))},
Some(&p) if p != e - 1 => {let o = s.clone(); *s = vec![e]; Some((true, o))},
_ => None,
}
})
.filter_map(|(n, v)| {
match n {
true => Some(v.clone()),
false => None,
}
})
.collect();
t
}
The chain is used to get the last vector.
I like the answers above but you could also use peekable() to tell if the next value is different.
https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html
I would probably use a fold for this?
That's because I'm very much a functional programmer.
Obviously mutating the accumulator is weird :P but this works too and represents another way of thinking about it.
This is basically a recursive solution and can be modified easily to use immutable datastructures.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=43b9e3613c16cb988da58f08724471a4
fn main() {
let v = vec![1, 2, 3, 5, 6, 7, 9, 10];
let mut res: Vec<Vec<i32>> = vec![];
let (last_group, _): (Vec<i32>, Option<i32>) = v
.iter()
.fold((vec![], None), |(mut cur_group, last), x| {
match last {
None => {
cur_group.push(*x);
(cur_group, Some(*x))
}
Some(last) => {
if x - last == 1 {
cur_group.push(*x);
(cur_group, Some(*x))
} else {
res.push(cur_group);
(vec![*x], Some(*x))
}
}
}
});
res.push(last_group);
println!("{:?}", res);
}

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.

Best way to remove elements of Vec depending on other elements of the same Vec

I have a vector of sets and I want to remove all sets that are subsets of other sets in the vector. Example:
a = {0, 3, 5}
b = {0, 5}
c = {0, 2, 3}
In this case I would like to remove b, because it's a subset of a. I'm fine with using a "dumb" n² algorithm.
Sadly, it's pretty tricky to get it working with the borrow checker. The best I've come up with is (Playground):
let mut v: Vec<HashSet<u8>> = vec![];
let mut to_delete = Vec::new();
for (i, set_a) in v.iter().enumerate().rev() {
for set_b in &v[..i] {
if set_a.is_subset(&set_b) {
to_delete.push(i);
break;
}
}
}
for i in to_delete {
v.swap_remove(i);
}
(note: the code above is not correct! See comments for further details)
I see a few disadvantages:
I need an additional vector with additional allocations
Maybe there are more efficient ways than calling swap_remove often
If I need to preserve order, I can't use swap_remove, but have to use remove which is slow
Is there a better way to do this? I'm not just asking about my use case, but about the general case as it's described in the title.
Here is a solution that does not make additional allocations and preserves the order:
fn product_retain<T, F>(v: &mut Vec<T>, mut pred: F)
where F: FnMut(&T, &T) -> bool
{
let mut j = 0;
for i in 0..v.len() {
// invariants:
// items v[0..j] will be kept
// items v[j..i] will be removed
if (0..j).chain(i + 1..v.len()).all(|a| pred(&v[i], &v[a])) {
v.swap(i, j);
j += 1;
}
}
v.truncate(j);
}
fn main() {
// test with a simpler example
// unique elements
let mut v = vec![1, 2, 3];
product_retain(&mut v, |a, b| a != b);
assert_eq!(vec![1, 2, 3], v);
let mut v = vec![1, 3, 2, 4, 5, 1, 2, 4];
product_retain(&mut v, |a, b| a != b);
assert_eq!(vec![3, 5, 1, 2, 4], v);
}
This is a kind of partition algorithm. The elements in the first partition will be kept and in the second partition will be removed.
You can use a while loop instead of the for:
use std::collections::HashSet;
fn main() {
let arr: &[&[u8]] = &[
&[3],
&[1,2,3],
&[1,3],
&[1,4],
&[2,3]
];
let mut v:Vec<HashSet<u8>> = arr.iter()
.map(|x| x.iter().cloned().collect())
.collect();
let mut pos = 0;
while pos < v.len() {
let is_sub = v[pos+1..].iter().any(|x| v[pos].is_subset(x))
|| v[..pos].iter().any(|x| v[pos].is_subset(x));
if is_sub {
v.swap_remove(pos);
} else {
pos+=1;
}
}
println!("{:?}", v);
}
There are no additional allocations.
To avoid using remove and swap_remove, you can change the type of vector to Vec<Option<HashSet<u8>>>:
use std::collections::HashSet;
fn main() {
let arr: &[&[u8]] = &[
&[3],
&[1,2,3],
&[1,3],
&[1,4],
&[2,3]
];
let mut v:Vec<Option<HashSet<u8>>> = arr.iter()
.map(|x| Some(x.iter().cloned().collect()))
.collect();
for pos in 0..v.len(){
let is_sub = match v[pos].as_ref() {
Some(chk) =>
v[..pos].iter().flat_map(|x| x).any(|x| chk.is_subset(x))
|| v[pos+1..].iter().flat_map(|x| x).any(|x| chk.is_subset(x)),
None => false,
};
if is_sub { v[pos]=None };//Replace with None instead remove
}
println!("{:?}", v);//[None, Some({3, 2, 1}), None, Some({1, 4}), None]
}
I need an additional vector with additional allocations
I wouldn't worry about that allocation, since the memory and runtime footprint of that allocation will be really small compared to the rest of your algorithm.
Maybe there are more efficient ways than calling swap_remove often.
If I need to preserve order, I can't use swap_remove, but have to use remove which is slow
I'd change to_delete from Vec<usize> to Vec<bool> and just mark whether a particular hashmap should be removed. You can then use the Vec::retain, which conditionaly removes elements while preserving order. Unfortunately, this function doesn't pass the index to the closure, so we have to create a workaround (playground):
let mut to_delete = vec![false; v.len()];
for (i, set_a) in v.iter().enumerate().rev() {
for set_b in &v[..i] {
if set_a.is_subset(&set_b) {
to_delete[i] = true;
}
}
}
{
// This assumes that retain checks the elements in the order.
let mut i = 0;
v.retain(|_| {
let ret = !to_delete[i];
i += 1;
ret
});
}
If your hashmap has a special value which can never occur under normal conditions, you can use it to mark a hashmap as "to delete", and then check that condition in retain (it would require changing the outer loop from iterator-based to range-based though).
Sidenote (if that HashSet<u8> is not just a toy example): More eficient way to store and compare sets of small integers would be to use a bitset.

Resources