首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么HashMap有iter_mut(),但是HashSet没有?

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

Stack Overflow用户
提问于 2016-03-13 12:27:50
回答 2查看 3.3K关注 0票数 7

在铁锈中为iter_mut函数提供HashMap而不是HashSet的设计原理是什么?

自行其是是一种失礼(假设这甚至是可以做到的)?

有一个可以缓解引起

X的前一次借用发生在这里;不变的借入阻止X的后续移动或可变借用,直到借款结束为止。

示例

一个非常复杂的例子(要点),它没有显示为什么参数传递是它的方式。有一个简短的评论来解释痛点:

代码语言:javascript
复制
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);
}

声明

代码语言:javascript
复制
while let Some(u) = unprocessed.iter().next() {

是一成不变的借用,因此

代码语言:javascript
复制
derp(*u, &mut unprocessed);

是不可能的,因为未经加工的东西是不能变异借来的。不变的借入直到时间循环结束才能结束。

我尝试过使用此为参考,最终试图通过各种赋值排列欺骗借入检查器,包括大括号,但由于预期表达式的耦合,问题仍然存在。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-13 15:55:09

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

代码语言:javascript
复制
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);
    }   
}

如果类型不是Copy,或者复制/克隆成本太高,您可以将它们包装在RcArc中,并在使用cloned()迭代它们时克隆它们(克隆RcArc并不克隆底层值,它只是克隆Rc指针并增加引用计数器)。

代码语言:javascript
复制
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));
}
票数 4
EN

Stack Overflow用户

发布于 2016-03-13 12:32:03

你必须考虑一下HashSet到底是什么。从IterMut获得的HashMap::iter_mut()仅在值部分:(&key, &mut val),((&'a K, &'a mut V))上是可变的。

HashSet基本上是一个HashMap<T, ()>,所以实际值是键,如果要修改键,则必须更新它们的散列,否则就会得到无效的HashMap

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35970238

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档