为什么HashMap有iter_mut()但HashSet没有?

Fil*_*erg 2 idiomatic standard-library rust

什么是用于提供设计原理iter_mut的功能HashMap,但不是HashSet在锈?

卷一个人自己是否是一个失礼(假设甚至可以做到)?

拥有一个可以缓解导致的情况

以前的借款X发生在这里; 在X借入结束之前,不可变借款会阻止后续移动或可变借款

一个非常复杂的例子(Gist),它没有显示参数传递的原因.有一个简短的评论解释痛点:

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);
}
Run Code Online (Sandbox Code Playgroud)

该声明

while let Some(u) = unprocessed.iter().next() {
Run Code Online (Sandbox Code Playgroud)

因此,是一种不可变的借款

derp(*u, &mut unprocessed);
Run Code Online (Sandbox Code Playgroud)

是不可能的,因为未经处理的人不能互相借用.不可变借用直到while循环结束才结束.

我试图用它作为参考,并且最终试图通过各种赋值的排列来欺骗借用检查器,用括号括起来,但由于预期表达式的耦合,问题仍然存在.

Arj*_*jan 9

你必须考虑HashSet实际是什么.在IterMut你从得到HashMap::iter_mut()仅在值部分变更:(&key, &mut val)((&'a K, &'a mut V))

HashSet基本上是一个HashMap<T, ()>,所以实际的值是键,如果你要修改键,它们的哈希值必须更新,否则你将无效HashMap.


Fra*_*gné 4

如果您HashSet包含Copy类型,例如i32,您可以处理该值的副本以尽早释放借用HashSet。为此,您需要消除表达式中绑定的所有借用while let。在您的原始代码中,u是 类型&i32,并且它一直借用 fromunprocessed直到循环结束。如果我们将模式更改为Some(&u),则u是 类型i32,它不会借用任何东西,因此我们可以随意使用unprocessed

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

    while let Some(&u) = unprocessed.iter().next() {
        derp(u, &mut unprocessed);
    }   
}
Run Code Online (Sandbox Code Playgroud)

如果类型不是Copy复制/克隆或者复制/克隆成本太高,您可以将它们包装在Rcor中Arc,并在使用迭代时克隆它们cloned()(克隆RcorArc不会克隆基础值,它只是克隆指针Rc并递增参考计数器)。

use std::collections::HashSet;
use std::rc::Rc;

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

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

    while let Some(u) = unprocessed.iter().cloned().next() {
        // If you don't use u afterwards,
        // you could also pass if by value to derp.
        derp(&u, &mut unprocessed);
    }   
}

fn main() {
    println!("Hello, world!");
    herp(Rc::new(10));
}
Run Code Online (Sandbox Code Playgroud)