Idiomatic way to remove entries from hashmap by condition and move their values out
⚓ Rust 📅 2026-03-26 👤 surdeus 👁️ 3Hello.
There is a hash map HashMap::<TaskId, sync::oneshot::Sender<TaskResult>>.
From time to time, some process:
- gets all keys from this map
- checks their status in external system
- if status is known, it sends it via the
Senderand removes the entry not to check it again.
But one shot sender moves itself into the method: oneshot::Sender::send(self, value) (it prevents oneshot from being called again)
So, I need to remove entry from the map (the only way to get value itself, as reference isn't enough).
I've come to several approaches, but all of them aren't elegant: I clone all keys, access map two times and so on.
// For all completed tasks report their status and remove them not to check them again
// Approach 1:
for task_id in map.keys().cloned().collect::<Vec<_>>() { // <-- redundant copy
if let Some(task_result) = get_task_result(task_id) {
map.remove(&task_id)
.expect("Can't be") // <-- silly
.send(task_result)
.unwrap();
}
}
// Approach 2:
let completed_tasks: Vec<_> = map
.keys()
.filter_map(|&task_id| get_task_result(task_id).map(|result| (task_id, result)))
.collect(); // <-- redundant copy
for (task_id, task_result) in completed_tasks {
map.remove(&task_id)
.expect("can't be") // <-- Silly
.send(task_result)
.unwrap();
}
There is HashMap::retain of course, but it can't tell in advance if I will remove an entry or not, so I get reference.
There is HashMap:extract_if, but it returns only key (taskId in my case) and value (sender) but doesn't allow me to map sender, so I can't send anything.
I wish there were something like mutable ref iterator over entities, i.e:
for entity in map.entities() {
let k:&Ket= entity.key();
// but at the same time
let v:Value = entitiy.remove_value_and_return_it()
}
I can solve it with RefCell probably, or with unsafe. But how would you solve it?
Thank you in advance.
PS: One might argue that iterating over keys is a bad idea, so they should better be stored in a vector. But I would need to synchronize both collections and still get value from the map.
2 posts - 2 participants
🏷️ Rust_feed