Creating a vector of structs with references

Rust noob here - I'm trying to initialize a vector of AccountInfo structs based on a hashmap of Vec<u8> values provided as the function argument.

fn initialize(keys: Vec<String>, arg: HashMap<String, Vec<u8>>) -> () {
  let mut account_infos: Vec<AccountInfo> = vec![];
  let pubkey = Pubkey::from_str(CONSTANTS).unwrap();

  for key in &keys {
    let data = arg.get_mut(&id).unwrap().as_mut_slice();
    account_infos.push(AccountInfo::new(
      &pubkey,
      false,
      false,
      bump.alloc(0),
      data,
      &pubkey,
      true,
      0,
    ));
  }

  // initialize other structs that use account_infos
   
  // spawn main tasks
 
}

But this fails with a compile error:

error[E0499]: cannot borrow `arg` as mutable more than once at a time
  --> src/market_manager.rs:76:32
   |
76 |                     let data = arg.get_mut(id).unwrap().as_mut_slice();
   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^ `arg` was mutably borrowed here in the previous iteration of the loop

I've tried changing the argument to HashMap<String, RefCell<Vec<u8>>> and borrowing from RefCell, but the compiler still refused to compile because the borrowed reference was retained outside the closure due to push.
I've run out of ideas - How can I create a vector of AccountInfos in this case?

get_mut borrows the hashmap mutably. Use get instead to borrow immutably.

Got a few points here:

  1. First of all, I don't think the code we can see is exhaustive enough and the compile error doesn't actually reflect the code we see.
  2. Your code moves the HashMap arg into the initialize function. In order to call get_mut, the HashMap needs to be declared as mutable, but your function definition doesn't reflect this requirement. Currently it's declared as immutable, if you need mutable access, you have to declare the arg as mutable: fn initialize(keys: Vec<String>, mut arg: HashMap<String, Vec<u8>>) { ... }
  3. How does the definition for AccountInfo look like? Do you really store a mutable slice &mut [u8] within this type? Since mutable references only allow single, exclusive access, no one else could read or modify this data anywhere else, but maybe this is fine for your business logic. But if not, this means you could simply move ownership of the whole Vec<u8> from the HashMap to your AccountInfo type. This could be done by calling the remove() method on the HashMap arg:
let data = arg.remove(&id).unwrap();
account_infos.push(AccountInfo::new(..., data, ...);

// AccountInfo would then need store a Vec<u8> instead of &mut[u8] of course...
  1. If your code needs to access the data of the HashMap mutably in various places, you need to wrap your HashMap within a type that allows interior mutability and then wrap it inside a reference counted type. For single threaded access this would be for example Rc<RefCell<HashMap<String, Vec<u8>>>> and for multithreaded access Arc<Mutex<HashMap<String, Vec<u8>>>.

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.