Hello everyone,
I am just trying to get into systems programming/rust, and was trying to write some code similar to this
use rand::Rng;
use std::collections::HashMap;
use std::fmt;
#[derive(Debug,Clone)]
pub struct UserNotFoundError;
impl fmt::Display for UserNotFoundError{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
write!(f, "USer not found error")
}
}
struct UserRecord{
user_id: u32,
user_name: String,
password: String,
age: u8
}
struct UserGroup{
users: HashMap<u32, UserRecord>,
group_id: u32,
group_name: String
}
impl UserGroup{
pub fn new(group_name: String, group_id: u32) -> Self{
return UserGroup{users: HashMap::new(),group_id, group_name};
}
fn load_user_from_disk(&mut self, user_id: u32){
let curr_user = UserRecord{user_id: user_id, user_name: String::from("Random_String"), password: String::from("random_password"), age: 12};
self.users.insert(user_id, curr_user);
}
pub fn get_or_add_user(&mut self, user_id: u32) -> Result<&UserRecord,UserNotFoundError>{
if let Some(user_record) = self.users.get(&user_id){
return Ok(user_record);
}else{
self.load_user_from_disk(user_id);
if let Some(user_record) = self.users.get(&user_id){
return Ok(user_record);
}else{
return Err(UserNotFoundError)
}
}
}
}
fn main() {
let mut curr_user_group = UserGroup::new(String::from("random_group"), 12312312);
let mut rng = rand::thread_rng();
let new_user_id: u32 = rng.gen();
curr_user_group.get_or_add_user(new_user_id);
}
Essentially what I am trying to do is:
- I want to expose a struct method that hands out mutable references to another struct stored in a hash map.
- Incase the required struct is not there, we load it from the disk/db, set it in the hashmap and then return the reference to the struct.
However I get the error
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:43:13
|
39 | pub fn get_or_add_user(&mut self, user_id: u32) -> Result<&UserRecord,UserNotFoundError>{
| - let's call the lifetime of this reference `'1`
40 | if let Some(user_record) = self.users.get(&user_id){
| ------------------------ immutable borrow occurs here
41 | return Ok(user_record);
| --------------- returning this value requires that `self.users` is borrowed for `'1`
42 | }else{
43 | self.load_user_from_disk(user_id);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` (bin "playground") due to previous error
I am not able to figure out how to solve this. I did see a bunch of questions with varied answers:
-
Introduce a separate block for the code that checks if the key exists in the hashmap or not. - Tried, did not work.
-
Split the functionality - I am not sure how I can split this up? This is fairly normal is high level languages. If we can't do this here, then can someone please explain why and what's a good way to think about this ? I just want an implementation that hides the complexity as such.