Borrowing mix of Mutable and Immutable references to contents of Hashmap at different indices in the same scope

I have been trying to find a way to get more than one (mutable-) reference from a Hashmap at different indices and return it as a result of a function/macro.
For this i have been experimenting with Rc<RefCell>> combinations but whenever i allways run into some problem.

Minimum example of what i am trying to do:

fn get_data(map: &HashMap<usize, Rc<RefCell<ArrayD<isize>>>>, index: usize) -> Option<ArrayViewMut<isize, Ix1>> {
    match map.get(&index) {
        Some(data) => {
            Some(data.borrow_mut().slice_mut(s![..]))
        },
        _ => None
    }
}

fn main() {
    let mut example: HashMap<usize, Rc<RefCell<ArrayD<isize>>>> = HashMap::new();
    example.insert(0, Rc::new(RefCell::new(Array::from_elem(IxDyn(&[3]), 0))));
    example.insert(1, Rc::new(RefCell::new(Array::from_elem(IxDyn(&[3]), 1))));
    example.insert(2, Rc::new(RefCell::new(Array::from_elem(IxDyn(&[3]), 2))));
    let mut sum = get_data(&example, 0).unwrap();
    let value1 = get_data(&example, 1).unwrap();
    let value2 = get_data(&example, 2).unwrap();
    let temp = &value1 + &value2;
    sum.assign(&temp);
}

I have already read through this topic, but there he needs to modify his reference only once but in my case i need the same reference at multiple locations.

Based on this topic one might think that changing to Vec instead of Hashmap could work based on the example. But in the final version the Hashmap indices are different so that would not work.

I have also looked at the nightly feature that is described in this topic, but here you can only get references as a group and not individually. This is a problem for me as i dont allways know which indices to get at compile time.

My question therefore is:
Is there a way for me to make sure that the arrayView(-Mut) can be returned without the compiler complaining that it outlives "res"?
If the above is not possible:
Is there a better way to get multiple individual references from a Hashmap simultaneously?

EDIT: fixed duplicate indices in given example resulting in runtime panic

In this SO answer the suggestion is to use HashBrown's HashMap, since it's API includes a get_many_mut method for getting multiple mutable references.

Would that work for your use case?

1 Like

that is the nightly feature i am referencing in the secound last paragraph

Not with this data structure. borrow_mut() returns what is basically a write lock granting access to the ArrayD within. Once you drop the lock, you lose the access. You could return the lock, or a newtype around it.

But then you'll panic at runtime with the example given...

    let mut value1 = get_data(&example, 0).unwrap();
    let mut value2 = get_data(&example, 0).unwrap();
    let temp = &value1.slice_mut(s![..]) + &value2.slice_mut(s![..]);

...because it is UB to have two &mut to the same memory.

You can get as many shared references from a HashMap at one time as you want (which my playground does accomplish, before panicking), which is usually all you need when the contents are interior mutability based (like Rc<RefCell<_>>).

that double 0 is a typo in the example will correct now

Here's a version of the modified OP using a newtype. (Probably there's a better name for the output of the Add implementation; ndarray is type alias heavy.)

could work but what i am trying to prevent is having to handle the slicing multiple times which is why in this version of the problem which resembles the original code more closely i am trying to return the ArrayViewMut directly instead of first the Array if there was some way for me to attach a lifetime to the borrow of data and the Array view i would not have this problem but from what i have found sofar that does not seem possible

Correct, it's not possible to keep the ArrayViewMut around after the RefMut goes away.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.