Mutating values held in a Hashmap.
I have a structure RoloGuiState. Which has a
rolodex: Option<RolodexBase>.
RolodexBase has a bunch of content. For now, the one that matters is a Vec.
mut guistate: &mut RoloGuiState,
message: CategoryMessage,
) -> iced::Task<Message> {
...
if let Some(dex) = &mut guistate.rolodex {
guistate.database_dirty = true;
match cat {
CategoryType::Short => dex.del_short_cat(instr),
Which results in the error:
dex` is a `&` reference, so it cannot be borrowed as mutable
This worked when I was using RefCell / Rc. So how do I mutate the vectors without the RefCell / Rc?
For completeness, when I had RefCell / Rc, I used just dex rather than (*dex), and I had a clone, which for a an Rc I knew wouldn't mess anything up. And I had tested it and it worked.
Thanks,
Joel
#[derive(Debug, Clone)]
// Base structure (object) for the rolodex.
// This owns all people (and, once implemented, organizations)
// it also holds various lists of labels used in people, etc.
pub struct RolodexBase {
// if non-empty, the name of the file used to build the rolodex
name: String,
// All the people stored in the rolodex
max_person_id: usize,
people: HashMap<usize, Person>,
// categories of relatively short string annotations
shortcategories: Vec<String>,
// categories of relatively long string annotations
longcategories: Vec<String>,
// labels usable with each category
categorylabels: HashMap<String, Vec<String>>,
// labels for use with associations between people
assoclabels: Vec<String>,
}
...
// delete s short category name, and all its sub-labels
pub fn del_short_cat(&mut self, name: String) {
let mut found = false;
let mut index = 0;
for val in self.shortcategories.iter() {
if *val == name {
found = true;
} else if !found {
index += 1;
}
}
if found {
self.shortcategories.remove(index);
if self.categorylabels.contains_key(&name) {
self.categorylabels.remove(&name);
}
}
}
....
pub struct RoloGuiState {
rolodex: Option<RolodexBase>,
main_state: MainPanelGuiState,
category: category_gui::CategoryState,
people: person_gui::PeopleGuiState,
database_dirty: bool,
mainpanel_dirty: bool,
}
....
impl RoloGuiState {
....
fn update(&mut self, message: Message) -> iced::Task<Message> {
match message {
....
Message::CategoryMessages(mess) => {
return (category_gui::category_update(self, mess));
}
....
pub fn category_update(
mut guistate: &mut RoloGuiState,
message: CategoryMessage,
) -> iced::Task<Message> {
match message {
CategoryMessage::DelCategoryPressed(cat, instr) => {
if let Some(dex) = &mut guistate.rolodex {
guistate.database_dirty = true;
match cat {
CategoryType::Short => dex.del_short_cat(instr),
CategoryType::Long => dex.del_long_cat(instr),
CategoryType::Assoc => dex.del_assoc_label(instr),
CategoryType::Subsidiary => {
if !guistate.category.subcat_selection.is_empty() {
dex.del_cat_label(guistate.category.subcat_selection.clone(), instr);
}
}
}
}
}
```
If there are things I missed, jsut ask and I will ad them.
Yours,
Joel
-*- mode: compilation; default-directory: "c:/Users/jmh/OneDrive/Documents/rust projects/rolodex/" -*-
Compilation started at Sun Mar 1 17:39:11
cargo build
Compiling rolodex v0.1.0 (C:\Users\jmh\OneDrive\Documents\rust projects\rolodex)
error[E0596]: cannot borrow `*dex` as mutable, as it is behind a `&` reference
--> src\rolo_window\category_gui.rs:89:25
|
89 | (*dex).add_short_cat(guistate.category.short_entry.clone());
| ^^^^^^ `dex` is a `&` reference, so it cannot be borrowed as mutable
error[E0596]: cannot borrow `*dex` as mutable, as it is behind a `&` reference
--> src\rolo_window\category_gui.rs:93:25
|
93 | (*dex).add_long_cat(guistate.category.long_entry.clone());
| ^^^^^^ `dex` is a `&` reference, so it cannot be borrowed as mutable
error[E0596]: cannot borrow `*dex` as mutable, as it is behind a `&` reference
--> src\rolo_window\category_gui.rs:97:25
|
97 | (*dex).add_assoc_label(guistate.category.assoc_entry.clone());
| ^^^^^^ `dex` is a `&` reference, so it cannot be borrowed as mutable
error[E0596]: cannot borrow `*dex` as mutable, as it is behind a `&` reference
--> src\rolo_window\category_gui.rs:101:29
|
101 | ... (*dex).add_cat_label(
| ^^^^^^ `dex` is a `&` reference, so it cannot be borrowed as mutable
error[E0507]: cannot move out of `guistate.rolodex` which is behind a shared reference
--> src\rolo_window\category_gui.rs:120:17
|
120 | let rolo = &guistate.rolodex.unwrap();
| ^^^^^^^^^^^^^^^^ -------- `guistate.rolodex` moved due to this method call
| |
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| move occurs because `guistate.rolodex` has type `Option<RolodexBase>`, which does not implement the `Copy` trait
|
note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `guistate.rolodex`
--> C:\Users\jmh\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\core\src\option.rs:1013:25
|
1013 | pub const fn unwrap(self) -> T {
| ^^^^
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
120 | let rolo = &<Option<RolodexBase> as Clone>::clone(&guistate.rolodex).unwrap();
| +++++++++++++++++++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
120 | let rolo = &guistate.rolodex.clone().unwrap();
| ++++++++
error[E0507]: cannot move out of `guistate.category.subcat_selectopt` which is behind a shared reference
By the way, you can get rid of those (*dex) and replace them with just dex. Explicitly dereferencing (or referencing) is very rarely necessary for a method call — it only happens when there is a same-named method for the reference you're dereferencing, such as if the reference and the referent both implement the same trait and you need the inner one.