Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does HashMap have iter_mut() but HashSet doesn't?

What is the design rationale for supplying an iter_mut function for HashMap but not HashSet in Rust?

Would it be a faux pas to roll one's own (assuming that can even be done)?

Having one could alleviate situations that give rise to

previous borrow of X occurs here; the immutable borrow prevents subsequent moves or mutable borrows of X until the borrow ends

Example

An extremely convoluted example (Gist) that does not show-case why the parameter passing is the way that it is. Has a short comment explaining the pain-point:

use std::collections::HashSet;

fn derp(v: i32, unprocessed: &mut HashSet<i32>) {
    if unprocessed.contains(&v) {

        // Pretend that v has been processed
        unprocessed.remove(&v);
    }   
}

fn herp(v: i32) {
    let mut unprocessed: HashSet<i32> = HashSet::new();
    unprocessed.insert(v);

    // I need to iterate over the unprocessed values
    while let Some(u) = unprocessed.iter().next() {

        // And them pass them mutably to another function
        // as I will process the values inside derp and
        // remove them from the set.
        //
        // This is an extremely convoluted example but
        // I need for derp to be a separate function
        // as I will employ recursion there, as it is
        // much more succinct than an iterative version.
        derp(*u, &mut unprocessed);
    }   
}

fn main() {
    println!("Hello, world!");
    herp(10);
}

The statement

while let Some(u) = unprocessed.iter().next() {

is an immutable borrow, hence

derp(*u, &mut unprocessed);

is impossible as unprocessed cannot be borrowed mutably. The immutable borrow does not end until the end of the while-loop.

I have tried to use this as reference and essentially ended up with trying to fool the borrow checker through various permutations of assignments, enclosing braces, but due to the coupling of the intended expressions the problem remains.

like image 505
Filip Allberg Avatar asked Dec 07 '22 23:12

Filip Allberg


1 Answers

You have to think about what HashSet actually is. The IterMut that you get from HashMap::iter_mut() is only mutable on the value part: (&key, &mut val), ((&'a K, &'a mut V))

HashSet is basically a HashMap<T, ()>, so the actual values are the keys, and if you would modify the keys the hash of them would have to be updated or you get an invalid HashMap.

like image 110
Arjan Avatar answered Dec 10 '22 11:12

Arjan