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

如何在不克隆键的情况下从HashMap中移除找到的条目?

在Rust的HashMap中无需克隆键即可移除找到的条目

我需要在HashMap中找到“最不常用”的条目并将其移除。由于键是从HashMap本身获取的引用,如何在不克隆键的情况下用它来移除条目?

示例代码:

use std::collections::HashMap;

fn main() {
    let mut usage = HashMap::<String, usize>::new();
    
    usage.insert("entry one".to_owned(), 5);
    usage.insert("entry two".to_owned(), 1);
    
    let mut least_used: Option<(&String, &usize)> = None;
    for curr in usage.iter() {
        if let Some(prev) = least_used {
            if curr.1 < prev.1 {
                least_used = Some(curr);
            }
        } else {
            least_used = Some(curr);
        }
    }
    
    println!("{:?}", least_used);
    
    usage.remove(least_used.unwrap().0);
}

遇到的错误:

cannot borrow usage as mutable because it is also borrowed as immutable


问题原因

这个错误是Rust借用规则导致的:usage.iter()会创建HashMap的不可变借用,least_used持有了该借用返回的引用。当调用usage.remove()时需要对HashMap进行可变借用,此时不可变与可变借用同时存在,违反了借用检查规则。

解决方法(无需克隆键)

方法一:使用raw_entry_mut直接查找并移除

raw_entry_mut允许在同一个可变借用中完成查找和移除操作,既避免了借用冲突,也不需要克隆键:

use std::collections::HashMap;

fn main() {
    let mut usage = HashMap::<String, usize>::new();
    
    usage.insert("entry one".to_owned(), 5);
    usage.insert("entry two".to_owned(), 1);
    
    let removed_entry = {
        // 先获取最小使用次数
        let min_count = usage.values().copied().min().unwrap();
        
        // 查找并移除对应条目
        usage.raw_entry_mut()
            .find(|_, &mut count| count == min_count)
            .remove()
    };
    
    println!("移除的条目: {:?}", removed_entry);
    println!("剩余内容: {:?}", usage);
}

方法二:使用drain_filter批量移除(适用于多条目场景)

如果存在多个使用次数相同的“最不常用”条目,drain_filter可以一次性移除所有符合条件的条目,同样无需克隆键:

use std::collections::HashMap;

fn main() {
    let mut usage = HashMap::<String, usize>::new();
    
    usage.insert("entry one".to_owned(), 5);
    usage.insert("entry two".to_owned(), 1);
    usage.insert("entry three".to_owned(), 1);
    
    // 获取最小使用次数
    let min_count = usage.values().copied().min().unwrap();
    
    // 移除所有符合条件的条目
    let removed_entries: Vec<_> = usage.drain_filter(|_, mut count| *count == min_count).collect();
    
    println!("移除的条目: {:?}", removed_entries);
    println!("剩余内容: {:?}", usage);
}

方法三:拆分作用域释放借用

如果坚持先单独查找再移除,可以将查找逻辑放在独立作用域中,确保不可变借用在调用移除方法前完全释放,配合raw_entry_mut完成无克隆移除:

use std::collections::HashMap;

fn main() {
    let mut usage = HashMap::<String, usize>::new();
    
    usage.insert("entry one".to_owned(), 5);
    usage.insert("entry two".to_owned(), 1);
    
    let removed_entry = {
        // 作用域内完成查找,借用仅在此范围有效
        let least_used_key = usage.iter()
            .min_by_key(|&(_, &count)| count)
            .map(|(key, _)| key);
        
        // 不可变借用已释放,使用raw_entry_mut移除目标条目
        least_used_key.and_then(|key| {
            usage.raw_entry_mut()
                .from_key(key)
                .remove()
        })
    };
    
    println!("移除的条目: {:?}", removed_entry);
    println!("剩余内容: {:?}", usage);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 23:39:20