简体   繁体   中英

Cannot borrow `*self` as mutable more than once at a time; in combination with HashMap

This is my code:

use std::collections::HashMap;
struct Foo {
  pub map : HashMap<i32, String>
}
impl Foo {
  fn foo(&mut self, x: &String) -> i32 {
    // I'm planning to use/modify "x" here and also modify "self"
    42
  }
  fn bar(&mut self) -> i32 {
    let x = self.map.get_mut(&1).unwrap();
    self.foo(x)
  }
}

I'm getting:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:13:9
   |
12 |         let x = self.map.get_mut(&1).unwrap();
   |                 -------------------- first mutable borrow occurs here
13 |         self.foo(x)
   |         ^^^^^^^^^-^
   |         |        |
   |         |        first borrow later used here
   |         second mutable borrow occurs here

What's going on?

Modifying self and x here breaks memory safety (at least in the general situation, which is what Rust must deal with). Consider the following implementation of foo which is allowed by your signature (fixing &String to &str ):

fn foo(&mut self, x: &str) -> i32 {
    self.map.clear();
    println!("{}", x);
    42
}

But you're calling this with x being a reference to something inside of self.map . So x could be destroyed by the time it's used. That's invalid, and Rust can't prove you won't do that, because you said you might. (Kevin Anderson provides a helpful comment below if you're coming from a GC language like C# where "reference" has a different meaning.)

How to fix this depends on what you're really trying to do, though one approach would be to clone the string so it cannot be destroyed:

fn bar(&mut self) -> i32 {
    let x = self.map.get(&1).unwrap().clone();  // <== now you have a copy
    self.foo(&x)
}

Note this got rid of the get_mut() . It's unclear what that was for. If you need an exclusive ( mut ) reference into the map, then you'll need to do that separately, and you can't do that directly while also holding an exclusive reference to self for the reasons above. Remember that mut means "exclusive access," not "mutable." A side effect of having exclusive access is that mutation is allowed.

If you really need something along these lines, you need to wrap your values (String) in Arc so that you can maintain reference counts and have shared ownership. But I would first try to redesign your algorithm to avoid this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM