You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust HashSet随机删元素编译失败:无法定位不可变借用位置

问题原因

set.iter()会生成一个不可变迭代器,这个迭代器会不可变借用整个HashSet。choose方法返回的是迭代器中元素的引用(&i32),这个引用的生命周期和HashSet的不可变绑定在一起。当调用set.remove()时,需要对HashSet进行可变借用,而Rust的借用规则禁止同一时间存在不可变借用与可变借用,因此触发编译错误。

本质是:你拿到的num是原集合中元素的引用,这个引用还依赖原集合的存在,此时修改集合(删除元素)会导致引用可能变成悬空指针,Rust的借用检查器会直接阻止这种危险操作。

修复方案

针对Copy类型(如i32)

直接解引用复制元素值,切断与原集合的借用关系:

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();
    // 解引用获取值,num不再是引用
    let num = *set.iter().choose(&mut rng).unwrap();
    set.remove(&num);
}

针对非Copy类型(如String)

使用cloned()将迭代器中的引用转换为拥有所有权的元素:

use std::collections::HashSet;
use rand::seq::IteratorRandom;
fn main() {
    let mut set: HashSet<String> = HashSet::new();
    set.insert("hello".into()); set.insert("world".into());
    let mut rng = rand::thread_rng();
    // cloned()生成拥有所有权的元素迭代器,避免借用
    let num = set.iter().cloned().choose(&mut rng).unwrap();
    set.remove(&num);
}

通用方案:先收集到Vec再选择

把集合元素复制到Vec后再随机选取,彻底解除与原集合的绑定:

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 elements: Vec<_> = set.iter().cloned().collect();
    let num = elements.choose(&mut rng).unwrap();
    set.remove(num);
}

内容的提问来源于stack exchange,提问作者Chuchi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 03:10:24