当前位置: 首页 > 知识库问答 >
问题:

尝试删除并插入HashMap时的错误可变借用(E0502)

盖昊东
2023-03-14

我是一个生锈的初学者,并尝试使用HashMap

let mut r = HashMap::new();
let mut i = 2;
...
if r.contains_key(&i) {
    let v = r.get(&i).unwrap();
    r.remove(&i);
    r.insert(i, v+1);
}

现在,借用检查器抱怨说,rif-块的三行中是借用不可变的,然后是可变的,然后又是不可变的。我不明白发生了什么。。。我想既然getremoveinsert方法都有r作为隐式参数,那么这三个调用都借用了它。但是为什么remove调用中的借用是可变的呢?


共有2个答案

漆雕博
2023-03-14

问题是,在获取v时,您会保留一个不可变的引用。由于它是一个u64,只需隐式地克隆,因此不需要更多的引用:

let v = r.get(&i).unwrap().clone();

游戏场

子车飞文
2023-03-14
匿名用户

但是为什么在删除调用中的这个借是可变的呢?

问题是跨越:Rust允许任意数量的不可变借入或单个可变借入,它们不能重叠。

这里的问题是v是映射内容的引用,这意味着v的存在需要借用映射,直到v停止使用。因此,这与删除和插入调用重叠,并禁止它们。

现在有各种各样的方法来解决这个问题。由于在这种特定情况下,您使用的是u64,即Copy,因此您只需取消引用,它就会复制您从映射中获得的值,从而无需借用:

if r.contains_key(&i) {
    let v = *r.get(&i).unwrap();
    r.remove(&i);
    r.insert(i, v+1);
}

不过,它的灵活性有限,因为它只适用于Copy类型[0]。

在这种特定情况下,这可能没什么大不了的,因为Copy很便宜,但出于安全性和清晰性考虑,使用Rust提供的高级API还是更有意义的,因为您最终需要它们来处理不那么琐碎的类型。

最简单的方法是只使用get_mut:其中get返回一个选项

if let Some(v) = r.get_mut(&i) {
    *v += 1;
}

对于您的用例来说已经足够了。

第二个选择是入口应用编程接口,这将永远毁掉你的所有其他hashmap应用编程接口。我不是在开玩笑,其他所有语言都变得可笑地令人沮丧,你可能想避免点击那个链接(尽管你最终还是需要了解它,因为它解决了真正的借用和效率问题)。

它在这里并没有真正展示它的内容,因为你的用例很简单,而且比工作做得更多,但是无论如何,你可以把增量写为:

r.entry(i).and_modify(|v| *v+=1);

顺便说一句,在大多数语言中(当然在Rust中也是如此),当您在hashmap中插入一个项目时,如果有旧值,旧值就会被删除。所以删除调用已经是多余的,完全没有必要。

模式匹配一个选项(例如HashMap::get返回的选项)通常比痛苦地按程序执行所有低级位更安全、更干净、更快。

因此,即使不使用高级API,原始代码也可以简化为:

if let Some(&v) = r.get(&i) {
    r.insert(i, v+1);
}

我仍然推荐get_mut版本,因为它更简单,避免了双重查找,并且适用于非Copy类型,但YMMV。

与大多数语言不同的是,Rust的HashMap::插入返回旧值(f any),这不是一个问题,但在某些情况下可能很有用。

[0]以及通过显式调用来克隆对象。clone(),这可能会或可能不会转化为显著的性能影响,具体取决于要克隆的类型。

 类似资料:
  • 我在Spring Data JPA/EclipseLink环境中有一个实体(其主键不是由序列生成的),如下所示: 并且我正在尝试从表中删除一行并重新插入它(使用相同的主键)。 我的方法是调用deleteAll()来清理表,然后保存()新的实体: 但这给了我一个错误: 我做错了什么?我不明白为何要将该实体合并,而不是简单地将其删除后重新插入。 谢谢你的帮助!

  • 为了快速地将数据插入到数据库中,我一直在尝试生成一个巨大的SQL(大约200个查询),但由于某种原因,我得到了SQL错误,但不确定是什么导致了它。 错误: SQL错误(1064):您的SQL语法有错误;查看与您的MySQL server版本相对应的手册,以了解在第8行附近使用的正确语法 下面是我的一部分代码: 你可以在Pastebin上找到我的完整SQL。 不知道是什么原因造成的,因为后面的“6”

  • 我正在尝试在表a中插入外键(在phpmyadmin中): 将表A添加外键(id_B)引用B(id_B); 但我得到了一个错误: 表A的id_A为主键,表B的id_B为主键。这两个表都使用innoDB作为存储引擎,表A中的id_B列和表B中的id_B列具有相同的类型。 出了什么问题,我该如何解决?

  • 但这给了我这个错误: 我做错了什么?我不明白为什么它试图合并实体,而不是简单地在删除后重新插入它。 谢谢你的帮助!

  • 新数组列表 我用多头填充这个数组列表。 当我试图将其插入postgresql时,我使用以下方法: 使用JDBC模板。但是当我试图运行这段代码时,它在“ARRAY[?]”上给出了一个错误。但如果temp2是一个单一的数字,比如:1253214,它就可以工作。有人有主意吗? 我的错误是: PreparedStatementCallback;错误的SQL语法[UPDATE pb1plnitm SET p

  • 尝试使用此查询 #1064-您的SQL语法有错误; 表和几乎完全相同-有相同的列。 请求中有什么错误?