Rust借用检查器问题:不知道不可变借用发生在哪里,导致无法编译。

huangapple go评论71阅读模式
英文:

Rust Borrow Checker Question: Don't know where immutable borrow happens that prevents compiling

问题

我想要从 Rust 的 HashSet 中删除随机元素,但我的实现似乎同时使用了可变借用和不可变借用。我不明白这是在哪里发生的,也不知道如何修复它。

以下是一个简单的程序,它从 HashSet 中随机选择一个元素,然后将其删除。但我得到了以下编译器错误:

错误[E0502]: 无法将 `set` 作为可变引用借用,因为它同时被不可变引用借用了
 --> src/main.rs:9:5
  |
8 |     let num = set.iter().choose(&mut rng).unwrap();
  |               ---------- 不可变引用在这里出现
9 |     set.remove(num);
  |     ^^^^------^^^^^
  |     |   |
  |     |   后续调用使用了不可变引用
  |     可变引用在这里出现
英文:

I want to remove random elements from a Rust HashSet, but my implementation seems to use a mutable borrow and immutable borrow at the same time. I don't understand where this is happening, or how to fix it.

use std::collections::HashSet;
use rand::seq::IteratorRandom;
fn main() {
    let mut set: HashSet<i32> = HashSet::new();
    set.insert(2); set.insert(3);
    let mut rng = rand::thread_rng();
    let num = set.iter().choose(&mut rng).unwrap();
    set.remove(num);
}

Here is a simple program that randomly chooses an element from a HashSet and then removes it. But I'm getting the following compiler error:

error[E0502]: cannot borrow `set` as mutable because it is also borrowed as immutable
 --> src/main.rs:9:5
  |
8 |     let num = set.iter().choose(&mut rng).unwrap();
  |               ---------- immutable borrow occurs here
9 |     set.remove(num);
  |     ^^^^------^^^^^
  |     |   |
  |     |   immutable borrow later used by call
  |     mutable borrow occurs here

I don't see how a borrow occurs in set.iter() or set.remove().

答案1

得分: 4

陷阱在于 iter() 返回对元素的引用,因此 num 本身也是一个引用。具体而言,Rust 中的情况如下:

let num: &i32 = set.iter().choose(&mut rng).unwrap();

现在,你有一个名为 num 的引用,它会与后来想要的可变引用发生冲突。

修复方法是在调用 remove() 之前消除引用:

let num: i32 = *set.iter().choose(&mut rng).unwrap(); // 引用已移除
set.remove(&num); // 转换回引用,但是变成了局部变量

这解决了冲突。

如果目标是删除某个随机元素,你还可以使用 retain 和一个函数来删除随机索引,这意味着不需要引用特定元素。

英文:

The trap here is that iter() returns references to elements, and as such, num itself is a reference. More specifically, this is what it looks like to Rust:

let num : &i32 = set.iter().choose(&mut rng).unwrap();

Where now you have a reference num that's lingering and in conflict with the mutable reference you later want.

The fix is to get rid of the reference before calling remove():

let num : i32 = *set.iter().choose(&mut rng).unwrap(); // Reference removed
set.remove(&num); // Convert back to reference, but to local variable

That resolves the conflict.

If the goal is to remove some random element, you could also remove a random index with retain and a function, which means there's no reference to a specific element needed.

huangapple
  • 本文由 发表于 2023年6月16日 01:47:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76484278.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定