How to get mutable reference to object inside vec inside a struct in rust? - vector

I have a very basic problem in a rust relating to mutability of objects inside a vector. I have a need to get a mutable reference to an object from within a method of the struct as follows:
struct Allocator {
free_regions: Vec<Region>, // vec of free regions
used_regions: Vec<Region>, // vec of used regions
}
fn alloc(&self, layout: Layout) -> ! {
//I want to get this mutable reference in order to avoid copying large amount of data around
let region: &mut Region = self.free_regions.get_mut(index).expect("Could not get region");
//This fails with `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
}
I cannot change the function to use &mut self because this requirement is forced by a trait I'm trying to implement here. What is a proper way to get around this kind of issue? I need to be able to modify the data in those regions inside the Vec in the struct.

You need to use RefCell, or Mutex if it is shared between threads
struct Allocator {
free_regions: RefCell<Vec<Region>>, // vec of free regions
used_regions: RefCell<Vec<Region>>, // vec of used regions
}
fn alloc(&self, layout: Layout) -> ! {
//I want to get this mutable reference in order to avoid copying large amount of data around
let region: &mut Region = self.free_regions.borrow_mut().get_mut(index).expect("Could not get region");
//This fails with `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
}
You can find more info here https://doc.rust-lang.org/book/ch15-05-interior-mutability.html

Related

How to avoid cloning parts when changing a mutable struct while recursion over that struct

I try to go recursively through a rose tree. The following code also works as intended but I still have the problem that I need to clone the value due to issues with the borrow checker. Therefore, it would be nice if there is a way to change from cloning to something better.
Without the clone() rust complains (rightfully) that I borrow self mutable by looking at the child nodes and the second time in the closure.
The whole structure and code is more complicated and bigger than shown below but that are the core elements. Do I have to change the data structure or do I miss something obvious? If the data structure is the issue how would you change it?
Also, the NType enum seems kinda useless here but I have some additional kinds that I have to consider. Here Inner nodes always have children and Outer nodes never.
enum NType{
Inner,
Outer
}
#[derive(Eq, PartialEq, Clone, Debug)]
struct Node {
// isn't a i32 actually. In my real program it's another struct
count: i32,
n_type: NType,
children: Option<Vec<usize>>
}
#[derive(Eq, PartialEq, Clone, Debug)]
struct Tree {
nodes: Vec<Node>,
}
impl Tree{
pub fn calc(&mut self, features: &Vec<i32>) -> i32{
// root is the last node
self.calc_h(self.nodes.len() - 1, features);
self.nodes[self.nodes.len() - 1].count.clone()
}
fn calc_h(&mut self, current: usize, features: &Vec<i32>){
// do some other things to decide where to go into recursion and where not to
// also use the features
if self.nodes[current].n_type == Inner{
//cloneing is very expensiv and destroys the performance
self.nodes[current].children.as_ref().unwrap().clone().iter().for_each(|&n| self.calc_h(n, features));
self.do_smt(current)
}
self.do_smt(current)
}
}
Edit:
Lagerbaer suggested to use as_mut but that results into current being a &mut usize and that doesn't really solve the problem.
changed childs into children
The correct plural of child is children so this is what I will refer to in this answer. Presumably this is what childs means in your code.
Since node.children is already an Option, the best solution would be to .take() the vector out of the node at the start of the iteration and put it in at the end. This way we avoid holding a reference to tree.nodes during the iteration.
if self.nodes[current].n_type == Inner {
let children = self.nodes[current].children.take().unwrap();
for &child in children.iter() {
self.calc_h(child, features);
}
self.nodes[current].children = Some(children);
}
Note that the behavior is different from your original code in case of cycles, but this is not something you need to worry about if the rest of the tree is implemented correctly.

What is the right way to have multiple linked lists and move data between them in Rust?

What is the right way to have multiple std::collections::LinkedLists where the number of those lists is unknown at compile time?
I'm filling them with data as well as merging them (e.g. using append()).
I thought it would be good to have a vector that contains those lists, or contains references to those lists.
I have tried the following:
use std::collections::LinkedList;
fn listtest() {
let mut v: Vec<LinkedList<i32>> = Vec::new();
v.push(LinkedList::new()); // first list
v.push(LinkedList::new()); // second list
v[0].push_back(1); // fill with data
v[1].push_back(3); // fill with data
v[0].append(&mut v[1]); // merge lists
}
fn main() {
listtest();
}
This fails to compile because I have two mutable references of v when using append(). I also tried using Vec<&mut LinkedList<i32>>, but did not succeed.
What would be the right approach to this problem?
There is no right approach. One possibility is to use split_at_mut. This creates two separate slices, each of which can be mutated separately from the other:
use std::collections::LinkedList;
fn main() {
let mut v = vec![LinkedList::new(), LinkedList::new()];
v[0].push_back(1);
v[1].push_back(3);
{
let (head, tail) = v.split_at_mut(1);
head[0].append(&mut tail[0]);
}
println!("{:?}", v);
}
See:
How to get mutable references to two array elements at the same time?
How can I write data from a slice to the same slice?
How to operate on 2 mutable slices of a Rust array
etc.
Most collections have an iter_mut method that returns an iterator that yields mutable references to each item in the collection. And these references can all be used at the same time! (But the references must come from the same iterator; you can't use references coming from separate calls to iter_mut concurrently.)
use std::collections::LinkedList;
fn listtest() {
let mut v: Vec<LinkedList<i32>> = Vec::new();
v.push(LinkedList::new()); // first list
v.push(LinkedList::new()); // second list
v[0].push_back(1); // fill with data
v[1].push_back(3); // fill with data
let mut vi = v.iter_mut();
let first = vi.next().unwrap();
let second = vi.next().unwrap();
first.append(second); // merge lists
}
fn main() {
listtest();
}
Also remember that iterators have the nth method for doing the equivalent of next in a loop.

Cannot move out of borrowed content when borrowing a generic type

I have a program that more or less looks like this
struct Test<T> {
vec: Vec<T>
}
impl<T> Test<T> {
fn get_first(&self) -> &T {
&self.vec[0]
}
fn do_something_with_x(&self, x: T) {
// Irrelevant
}
}
fn main() {
let t = Test { vec: vec![1i32, 2, 3] };
let x = t.get_first();
t.do_something_with_x(*x);
}
Basically, we call a method on the struct Test that borrows some value. Then we call another method on the same struct, passing the previously obtained value.
This example works perfectly fine. Now, when we make the content of main generic, it doesn't work anymore.
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(*x);
}
Then I get the following error:
error: cannot move out of borrowed content
src/main.rs:14 let raw_x = *x;
I'm not completely sure why this is happening. Can someone explain to me why Test<i32> isn't borrowed when calling get_first while Test<T> is?
The short answer is that i32 implements the Copy trait, but T does not. If you use fn generic_main<T: Copy>(t: Test<T>), then your immediate problem is fixed.
The longer answer is that Copy is a special trait which means values can be copied by simply copying bits. Types like i32 implement Copy. Types like String do not implement Copy because, for example, it requires a heap allocation. If you copied a String just by copying bits, you'd end up with two String values pointing to the same chunk of memory. That would not be good (it's unsafe!).
Therefore, giving your T a Copy bound is quite restrictive. A less restrictive bound would be T: Clone. The Clone trait is similar to Copy (in that it copies values), but it's usually done by more than just "copying bits." For example, the String type will implement Clone by creating a new heap allocation for the underlying memory.
This requires you to change how your generic_main is written:
fn generic_main<T: Clone>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x.clone());
}
Alternatively, if you don't want to have either the Clone or Copy bounds, then you could change your do_something_with_x method to take a reference to T rather than an owned T:
impl<T> Test<T> {
// other methods elided
fn do_something_with_x(&self, x: &T) {
// Irrelevant
}
}
And your generic_main stays mostly the same, except you don't dereference x:
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x);
}
You can read more about Copy in the docs. There are some nice examples, including how to implement Copy for your own types.

Mutable structs in a vector

I'm trying to create a vector to keep track of enemies in a game that will hold a bunch of mutable structs. I have a world struct that has the enemies as a member of it as follows:
pub struct World {
pub player : Creature,
pub enemies : Vec<Creature>,
}
I create the enemies vector as follows:
let mut enemies = vec![];
let mut enemy = Creature::new(5, 5, map_start_x+5, map_start_y+5, "$", 10, 1, "")
enemies.push(enemy);
later on in the code when I pull out an individual enemy from enemies for attacking and try to update the hp as follows:
for enemy in self.enemies.iter() {
if new_x == enemy.x && new_y == enemy.y {
enemy.hp -= self.player.damage;
return;
}
}
which is where the problem occurs since enemy is apparently not mutable at this point
error: cannot assign to immutable field `enemy.hp`
Updated for the latest Rust version
Mutability in Rust is not associated with data structures, it is a property of a place (read: a variable) where the data is stored. That is, if you place a value in a mutable slot:
let mut world = World::new();
then you can take mutable references to this variable, and hence call methods which can mutate it.
Your structure owns all data it contains, so you can make it mutable any time you need. self.enemies.iter() returns an iterator which generates items of type &Creature - immutable references, so you can't use them to mutate the structure. However, there is another method on a vector, called iter_mut(). This method returns an iterator which produces &mut Creature - mutable references, which do allow changing data they point to.
for enemy in self.enemies.iter_mut() {
if new_x == enemy.x && new_y == enemy.y {
enemy.hp -= self.player.damage;
return;
}
}
// The following also works (due to IntoIter conversion)
for enemy in &mut self.enemies {
if new_x == enemy.x && new_y == enemy.y {
enemy.hp -= self.player.damage;
return;
}
}
Note that in order for this to work, you have to pass self by mutable reference too, otherwise it will be impossible to mutate anything under it, implying that you won't be able to obtain mutable references to internals of the structure, including items of the vector. In short, make sure that whatever method contains this loop is defined like this:
fn attack(&mut self, ...) { ... }
Vec<T>::iter() gives you an Iterator<&T> 1, i.e. an iterator over "immutable borrowed" pointers. If you want to mutate the contents, use Vec::iter_mut(), which is an Iterator<&mut T>.
In general, presence or absence of mut affects whether you can use some method, but not what each method means. This is not the whole truth (perhaps different traits with a method of the same name are implemented for & and &mut), but it's a good approximation.
1 I omitted the lifetime aspect of these types to make a point.

Mutable vectors in struct

I'm trying to get a graph clustering algorithm to work in Rust. Part of the code is a WeightedGraph data structure with an adjacency list representation. The core would be represented like this (shown in Python to make it clear what I'm trying to do):
class Edge(object):
def __init__(self, target, weight):
self.target = target
self.weight = weight
class WeightedGraph(object):
def __init__(self, initial_size):
self.adjacency_list = [[] for i in range(initial_size)]
self.size = initial_size
self.edge_count = 0
def add_edge(self, source, target, weight):
self.adjacency_list[source].append(Edge(target, weight))
self.edge_count += 1
So, the adjacency list holds an array of n arrays: one array for each node in the graph. The inner array holds the neighbors of that node, represented as Edge (the target node number and the double weight).
My attempt to translate the whole thing to Rust looks like this:
struct Edge {
target: uint,
weight: f64
}
struct WeightedGraph {
adjacency_list: ~Vec<~Vec<Edge>>,
size: uint,
edge_count: int
}
impl WeightedGraph {
fn new(num_nodes: uint) -> WeightedGraph {
let mut adjacency_list: ~Vec<~Vec<Edge>> = box Vec::from_fn(num_nodes, |idx| box Vec::new());
WeightedGraph {
adjacency_list: adjacency_list,
size: num_nodes,
edge_count: 0
}
}
fn add_edge(mut self, source: uint, target: uint, weight: f64) {
self.adjacency_list.get(source).push(Edge { target: target, weight: weight });
self.edge_count += 1;
}
}
But rustc gives me this error:
weightedgraph.rs:24:9: 24:40 error: cannot borrow immutable dereference of `~`-pointer as mutable
weightedgraph.rs:24 self.adjacency_list.get(source).push(Edge { target: target, weight: weight });
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, 2 main questions:
1. How can I get the add_edge method to work?
I'm thinking that WeightedGraph is supposed to own all its inner data (please correct me if I'm wrong). But why can add_edge not modify the graph's own data?
2. Is ~Vec<~Vec<Edge>> the correct way to represent a variable-sized array/list that holds a dynamic list in each element?
The tutorial also mentions ~[int] as vector syntax, so should it be: ~[~[Edge]] instead? Or what is the difference between Vec<Edge> and ~[Edge]? And if I'm supposed to use ~[~[Edge]], how would I construct/initialize the inner lists then? (currently, I tried to use Vec::from_fn)
The WeightedGraph does own all its inner data, but even if you own something you have to opt into mutating it. get gives you a & pointer, to mutate you need a &mut pointer. Vec::get_mut will give you that: self.adjacency_list.get_mut(source).push(...).
Regarding ~Vec<Edge> and ~[Edge]: It used to be (until very recently) that ~[T] denoted a growable vector of T, unlike every other type that's written ~... This special case was removed and ~[T] is now just a unique pointer to a T-slice, i.e. an owning pointer to a bunch of Ts in memory without any growth capability. Vec<T> is now the growable vector type.
Note that it's Vec<T>, not ~Vec<T>; the ~ used to be part of the vector syntax but here it's just an ordinary unique pointer and represents completely unnecessary indirection and allocation. You want adjacency_list: Vec<Vec<Edge>>. A Vec<T> is a fully fledged concrete type (a triple data, length, capacity if that means anything to you), it encapsulates the memory allocation and indirection and you can use it as a value. You gain nothing by boxing it, and lose clarity as well as performance.
You have another (minor) issue: fn add_edge(mut self, ...), like fn add_edge(self, ...), means "take self by value". Since the adjacency_list member is a linear type (it can be dropped, it is moved instead of copied implicitly), your WeightedGraph is also a linear type. The following code will fail because the first add_edge call consumed the graph.
let g = WeightedGraph::new(2);
g.add_edge(1, 0, 2); // moving out of g
g.add_edge(0, 1, 3); // error: use of g after move
You want &mut self: Allow mutation of self but don't take ownership of it/don't move it.
get only returns immutable references, you have to use get_mut if you want to modify the data
You only need Vec<Vec<Edge>>, Vec is the right thing to use, ~[] was for that purpose in the past but now means something else (or will, not sure if that is changed already)
You also have to change the signature of add_edge to take &mut self because now you are moving the ownership of self to add_edge and that is not what you want

Resources