0

I'm new to Rust and I met this situation which I think can be solved with more concise code, which is however rejected by the borrow checker. I'd like to know whether there's an alternative approach to it.

I'm trying to construct an inverted index. If the key is not previously in the HashMap, I have to create a new postings_list and insert it. If the key was already there, I will presumably have to only update the originally existing postings_list, instead of replacing it.

The code that is working (very long-winded):

if !terms.contains_key(term) {
    let mut postings_list = Vec::new();
    postings_list.push(posting_id);
    terms.insert(term.to_string(), postings_list);
} else {
    // try! can't even be used with Option... So I'm forced to write another match!
    // let postings_list = try!(terms.get_mut(term));

    match terms.get_mut(term) {
        Some(postings_list) => {
            postings_list.push(posting_id);
        },

        // It's impossible for this to happen...
        None => process::exit(999)
    }
}

However, I feel one call to get_mut should suffice:

match terms.get_mut(term) {
    None => {
        let mut postings_list = Vec::new();
        postings_list.push(posting_id);
        terms.insert(term.to_string(), postings_list);
    },
    Some(postings_list) => {
        postings_list.push(posting_id);
    }
}

The borrow checker says I borrowed a mutable reference twice, at terms.get_mut(term) and terms.insert(term.to_string(), postings_list);.

The problem for me is that apparently calling contains_key and also get_mut both would be much less efficient than just performing one check. Or did I get it wrong? Also, the above code is much uglier.

Am I doing this wrong? Or should I just not use get_mut, and should instead use get and then insert an updated postings_list again? Again, I'd think that would be much less efficient than simply operating on the original list stored in the HashMap itself. Or am I wrong?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
xji
  • 7,341
  • 4
  • 40
  • 61
  • 1
    Have you tried [entry](https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.entry)? – E_net4 Nov 20 '16 at 18:38
  • 1
    @E_net4: Or high-level methods such as `insert_or`, ... – Matthieu M. Nov 20 '16 at 18:39
  • 1
    `terms.entry(term).or_insert_with(Vec::new).push(posting_id)` – Shepmaster Nov 20 '16 at 18:41
  • @Shepmaster The point is I'm trying to append to an already existing vector, not create a new one. I wonder whether copying the original vector, appending, and then inserting would be much less efficient than directly mutating. – xji Nov 20 '16 at 18:42
  • @Shepmaster I don't think your code does exactly what I did with my code. You created a new vector. – xji Nov 20 '16 at 18:43
  • @JIXiang No, I did not; only when there wasn't previously a value. – Shepmaster Nov 20 '16 at 18:43
  • @Shepmaster OK. it seems I shall learn a bit more about `entry` then. Thanks for the quick answer. – xji Nov 20 '16 at 18:45

0 Answers0