Why does the borrow from `HashMap::get` not end wh

2019-03-04 11:38发布

问题:

Here is emulation of my problem, when a borrow ends too late

use std::collections::HashMap;

struct Item {
    capacity: u64
}

struct Petrol {
    name: String,
    fuel: HashMap<&'static str, Item>
}

fn buy_gaz(p: &mut Petrol) {
   match p.fuel.get("gaz") {
      Some(gaz) => {
        fire_petrol(p); 
      }
      None => ()
   }
}

fn fire_petrol(p: &mut Petrol) {
    println!("Boom!");
    p.fuel.remove("gaz");
    p.fuel.remove("benzin");
}

fn main() {
    let mut bt = Petrol {
        name: "Britii Petrovich".to_string(),
        fuel: HashMap::new()
    };

    bt.fuel.insert("gaz", Item { capacity: 1000 });
    bt.fuel.insert("benzin", Item { capacity: 5000 });

    buy_gaz(&mut bt);
}

When compiling I get:

note: previous borrow of `p.fuel` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `p.fuel` until the borrow ends
match p.fuel.get("gaz") {
      ^~~~~~

Why does the borrow end so late and not on exit from HashMap::get? How do I fix my case?

PS: I edited my first post for adding struct to HashMap, because decision below worked for simply types (with default Clone trait, I think), but doesn't work for custom structures

回答1:

If you look at the documentation of HashMap::get you can see, that it returns an Option<&V>. The reference into the map allows you to do zero-copy accesses into a hash-map. The downside is, as long as you have a reference, you cannot modify the hash map as that might invalidate your reference.

The branch Some(gaz) causes the binding gaz to have type &u64, where the reference points into your hashmap. If you change that to Some(&gaz) you get a copy of the value instead of a reference, and may modify the hash map even inside that branch.

Minimal Example in Playpen



标签: rust lifetime