2

I'm writing the "ArrayMap" object that includes the set of key and Vec in Rust. The following are the module and the test code.

use std::cell::{RefCell, RefMut};
use std::collections::HashMap;

pub struct ArrayMap {
    map: RefCell<HashMap<String, Vec<i32>>>,
}

impl ArrayMap {
    pub fn new() -> Self {
        let map = RefCell::new(HashMap::<String, Vec<i32>>::new());
        ArrayMap{map: map}
    }

    pub fn add(&self, key: &str) {
        self.map.borrow_mut().insert(key.to_string(), Vec::<i32>::new());
    }

    pub fn get(&self, key: &str) -> RefMut<Vec<i32>> {
        let map = self.map.borrow_mut();  // panic
        RefMut::map(map, |map| map.get_mut(key).unwrap())
    }
}
mod array_map;
use array_map::ArrayMap;

fn main() {
    let m = ArrayMap::new();
    m.add("array0");
    m.add("array1");
    let _a0 = m.get("array0");
    let _a1 = m.get("array1");
}

However, the error below occurs.

thread 'main' panicked at 'already borrowed: BorrowMutError', src\array_map.rs:19:28

I know it works if I divide two m.get() into other blocks but I don't want to do so for the actual usage.

And I tried to use Rc<RefCell> for the "map" of ArrayMap.

use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::rc::Rc;

pub struct ArrayMap {
    map: Rc<RefCell<HashMap<String, Vec<i32>>>>,
}

impl ArrayMap {
    pub fn new() -> Self {
        let map = Rc::new(RefCell::new(HashMap::<String, Vec<i32>>::new()));
        ArrayMap{map: map}
    }

    pub fn add(&self, key: &str) {
        self.map.borrow_mut().insert(key.to_string(), Vec::<i32>::new());
    }

    pub fn get(&self, key: &str) -> RefMut<Vec<i32>> {
        let map = Rc::clone(&self.map).borrow_mut();
        RefMut::map(map, |map| map.get_mut(key).unwrap())  // error[E0515]
    }
}

But this error occurs.

error[E0515]: cannot return value referencing temporary value
  --> src\array_map.rs:21:9

Could you please tell me the way to avoid this situation? Any ideas are welcome.

1 Answer 1

2

You cannot hold multiple RefMut at the same time, there must only be one RefMut that exist at any given time. This is enforced at runtime, and if this rule is violated, the program panics. This is what happend in the first case.

What you want is for get to return a Rc<RefCell<Vec<i32>>>, so you can hold multiple Rc to a vector and access it mutably whenever you want.

use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

pub struct ArrayMap<T> {
    map: HashMap<String, Rc<RefCell<Vec<T>>>>,
}

impl<T> ArrayMap<T> {
    pub fn new() -> Self {
        ArrayMap { map: HashMap::new() }
    }

    pub fn add(&mut self, key: &str, data: Vec<T>) {
        self.map.insert(key.to_string(), Rc::new(RefCell::new(data)));
    }

    pub fn get(&mut self, key: &str) -> Option<Rc<RefCell<Vec<T>>>> {
        self.map.get(key).cloned()
    }
}


fn main() {
    let mut am = ArrayMap::new();

    am.add("a", vec![1, 2, 3]);
    am.add("b", vec![4, 5, 6]);

    let a1 = am.get("a").unwrap();
    let a2 = am.get("a").unwrap();

    let b1 = am.get("b").unwrap();
    let b2 = am.get("b").unwrap();

    for a in a1.borrow_mut().iter_mut() {
        *a *= 2;
    }

    for b in b2.borrow_mut().iter_mut() {
        *b *= 3;
    }

    println!("{a1:?}, {a2:?}");
    println!("{b1:?}, {b2:?}")
}

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for your response. It works! I have also needed the generic implementation. I appreciate your help. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.