pre-RFC: Add a way to insert into a collection, then return a reference to the inserted item in one operation.
Nobody has claimed this yet.
- Dominant language
- Markdown
- Stars
- 6.6k
- Forks
- 1.7k
- Avg merge
- 16h 14m
- Merged PRs (30d)
- 1
Description
I ran across this issue today when I'm attempting to write a function like this:
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Player {
// fields omitted
}
struct PlayerList {
// other fields omitted
players: HashSet<Player>,
}
impl PlayerList {
/// Create a new player and insert it into the player list.
/// Then return a reference to this new player.
pub fn new_player(
&mut self,
// other fields omitted
) -> &Player {
let new = Player {};
self.players.insert(new);
todo!("return a reference to the new player")
}
}
To my surprise, there is no easy way to do this with HashSet, or for that matter, with any collection. I ended up having to write this:
pub fn new_player(&mut self) -> &Player {
let new = Player {};
self.players.insert(new.clone());
self.players.get(&new).unwrap()
}
This is obviously bad for a multitude of reasons:
- Unnecessary
Player::clonecall - Unnecessary
Hashset::getcall - Extra
unwrap - Generally bad ergonomics
So I asked on the Rust-lang discord guild here, and Yand.rs gave this solution:
use ::hashbrown::HashMap;
fn create_new(s: &mut HashMap<String, ()>) -> &str {
let new = String::from("…");
s.raw_entry_mut().from_key(&new).or_insert(new, ()).0
}
... but also had this to say:
Sadly it requires
raw_entry_mut(), which is either unstable, or requireshashbrown. And also only manual maps have these, sets don't for some reason
My proposition
Add a family of associated functions that provide this capability to all collections:
impl<T> Vec<T> {
pub fn insert_get(&mut self, index: usize, value: T) -> &T;
pub fn push_get(&mut self, value: T) -> &T;
}
impl<T> VecDeque<T> {
pub fn insert_get(&mut self, index: usize, value: T) -> &T;
// might be unnecessary, see questions
pub fn push_front_get(&mut self, value: T) -> &T;
// might be unnecessary, see questions
pub fn push_back_get(&mut self, value: T) -> &T;
}
impl<T> LinkedList<T> {
// might be unnecessary, see questions
pub fn push_front_get(&mut self, value: T) -> &T;
// might be unnecessary, see questions
pub fn push_back_get(&mut self, value: T) -> &T;
}
impl<K, V> HashMap<K, V> {
pub fn insert_get(&mut self, key: K, value: V) -> (&V, Option<V>);
// See https://github.com/rust-lang/rust/issues/82766#issuecomment-1301845589
pub fn insert_vacant_get(&mut self, key: K, value: V) -> (&V, Option<V>);
}
impl<K, V> BTreeMap<K, V> {
pub fn insert_get(&mut self, key: K, value: V) -> (&V, Option<V>);
// See https://github.com/rust-lang/rust/issues/82766#issuecomment-1301845589
pub fn insert_vacant_get(&mut self, key: K, value: V) -> (&V, Option<V>);
}
impl<T> HashSet<T> {
pub fn replace_get(&mut self, value: T) -> (&T, Option<T>);
}
impl<T> BTreeSet<T> {
pub fn replace_get(&mut self, value: T) -> (&T, Option<T>);
}
impl<T> BinaryHeap<T> {
pub fn push_get(&mut self, value: T) -> &T;
}
Potential questions
- The names are descriptive but not very elegant IMO. Are there better ones?
- Should there be
*_get_mutvariants too? -
VecDequeandLinkedListalready havefrontandbackmethods. Do they makepush_front_getandpush_back_getredundant? - In the return type of maps and sets, should the order of tuple members be flipped? (i.e.
(Option<V>, &V)instead) - For maps, should the return type contain a reference to the key as well? (i.e.
(&K, &V, Option<V>)or((&K, &V), Option<V>))
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Begin with the proposed collection APIs in the issue and review the linked #82766 discussion; no implementation file or test is named. Done means settling the API names, return types, and *_get_mut/key-reference questions in an accepted RFC before implementation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100