Reputation: 3780
I have a table organised as columns, and I want to create a vector of rows which are hash maps whose values are mutable references to the equivalent values in the columns, so that I can then iterate over the rows, change the values which will update the values in the original columns. I think it might be to create an iterator of rows, rather than a vector of rows, but I would prefer to first learn how to do a vector (if possible) since this project is for the purpose of me learning rust. Below is what I have so far, but I am getting the error
cannot borrow `columns` as mutable more than once at a time
`columns` was mutably borrowed here in the previous iteration of the loop
which I can't find a solution to. In the below I create columns
which holds the original data, rows
which should hold references to the data in columns
, and then I try to update columns
by getting cell
from rows
and assigning a new value to it.
use std::collections::HashMap;
#[derive(Debug)]
struct Column {
name: String,
data: Vec<i32>,
}
fn main() {
let mut columns = vec![
Column {
name: String::from("col1"),
data: vec![4, 5, 6],
},
Column {
name: String::from("col2"),
data: vec![7, 8, 9],
},
];
println!("{:?}", columns);
let mut rows = Vec::new();
let columns_len = columns[0].data.len();
for i in 0..columns_len {
let mut row = HashMap::new();
for column in columns.iter_mut() {
row.insert(&column.name, column.data.get_mut(i).unwrap());
}
rows.push(row);
}
println!("{:?}", rows);
let cell = rows
.get_mut(1)
.unwrap()
.get_mut(&String::from("col2"))
.unwrap();
println!("{:?}", cell);
**cell = 99;
println!("{:?}", columns);
println!("{:?}", rows);
println!("{:?}", cell);
}
Upvotes: 1
Views: 471
Reputation: 98436
Many times it is useful to think of mutable references as exclusive references. That is, instead of thinking that they allow you to modify the value, think of them as guaranteeing that this is the only live reference that can use that valule, and that the mutability thing is just a nice side effect.
With that in mind, if you manage to get a Vec
of mutable references to the individual values of your columns
, then the columns
themselves will be inaccesible (remember, exclusive access).
And when you create cell
that is an exclusive reference to the rows
vector, then this vector will be inaccessible for the lifetime of cell
.
That said, you can create an array of mutable references to the contents of your columns
, as long as you are careful with the iterator API (the get_mut()
will not do because the compiler cannot assure that you do not use the same index twice):
// First create the hash maps
let mut rows = std::iter::repeat_with(|| HashMap::new())
.take(columns[0].data.len())
.collect::<Vec<_>>();
// Then fill in the references.
for c in columns.iter_mut() {
for (id, d) in c.data.iter_mut().enumerate() {
rows[id].insert(c.name.as_str(), d);
}
}
Note that the rows
variable has type: Vec<HashMap<&str, &mut i32>>
, that I don't know if it will be so useful.
In practical Rust, many times it is easier to store the index of a value in the Vec
instead of the reference to the inner value. You may think that it is not so efficient, but think of what would happen if you push into the vector and it has to reallocate its inner memory!
Upvotes: 1