Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hash_map::Entry.or_insert_with_key() method #1202

Closed
dnspies opened this issue Jul 11, 2015 · 7 comments
Closed

Add hash_map::Entry.or_insert_with_key() method #1202

dnspies opened this issue Jul 11, 2015 · 7 comments
Labels
T-libs-api Relevant to the library API team, which will review and decide on the RFC.

Comments

@dnspies
Copy link

dnspies commented Jul 11, 2015

In some cases, I only have one key, and by calling

let e = my_hash_map.entry(k);

I'm giving up my one and only instance of k.
Now I need to use k to populate the entry (imagine my_hash_map memoizes the function my_fun):

e.or_insert_with(|| my_fun(&k))

but I'm out of luck because k has been stolen by the call to entry (k has been moved). By adding an extra function to entry, this can be rectified by

e.or_insert_with_key(|kref| my_fun(kref))
@Gankra
Copy link
Contributor

Gankra commented Jul 11, 2015

I would really rather just expose a key method for retrieving the key on VacantEntry and OccupiedEntry.

See #1194

@dnspies
Copy link
Author

dnspies commented Jul 13, 2015

I don't think that works.
As soon as I call e.get_key() I'm now holding an immutable ref into e so now I can't call any mutable methods on e (such as or_insert_with()) until I drop it.
I suppose one alternative approach would be to have a:

e.get_key_and_value()
which returns a pair of both an immutable ref to the key and also a mutable ref to the value.
And then call or_insert() on the value ref.
But that requires a much bigger change to the way Entry works.

@Diggsey
Copy link
Contributor

Diggsey commented Jul 13, 2015

@dnspies What you're trying to do is fundamentally unsafe - you can't put a value into a map which keeps a reference to its own key. You can use such a reference to construct the value, in which case @gankro's solution will work, because the borrow will expire after construction, and you can then call mutable methods on the entry again.

@dnspies
Copy link
Author

dnspies commented Jul 13, 2015

That won't work with or_insert_with which clearly must be called with both borrows. Of course, I could avoid using that method and instead just match against the entry to see if it's vacant or not. In that case get_key() is sufficient.

@nrc nrc added the T-libs-api Relevant to the library API team, which will review and decide on the RFC. label Aug 25, 2016
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Apr 11, 2020
Add or_insert_with_key to Entry of HashMap/BTreeMap

Going along with `or_insert_with`, `or_insert_with_key` provides the `Entry`'s key to the lambda, avoiding the need to either clone the key or the need to reimplement this body of this method from scratch each time.

This is useful when the initial value for a map entry is derived from the key. For example, the introductory Rust book has an example Cacher struct that takes an expensive-to-compute lambda and then can, given an argument to the lambda, produce either the cached result or execute the lambda.

---

I'm fairly new to Rust, so any optimizations, corrections to types, better names, better documentation, or whatever else would be appreciated. I'd like to thank Arnavion on freenode for helping me to implement a very similar method when I found that `or_insert_with_key` was unavailable.

As a somewhat-related note, this implements rust-lang/rfcs#1202 from 2015, so if this pull request is accepted, that should be closed.
Centril added a commit to Centril/rust that referenced this issue Apr 11, 2020
Add or_insert_with_key to Entry of HashMap/BTreeMap

Going along with `or_insert_with`, `or_insert_with_key` provides the `Entry`'s key to the lambda, avoiding the need to either clone the key or the need to reimplement this body of this method from scratch each time.

This is useful when the initial value for a map entry is derived from the key. For example, the introductory Rust book has an example Cacher struct that takes an expensive-to-compute lambda and then can, given an argument to the lambda, produce either the cached result or execute the lambda.

---

I'm fairly new to Rust, so any optimizations, corrections to types, better names, better documentation, or whatever else would be appreciated. I'd like to thank Arnavion on freenode for helping me to implement a very similar method when I found that `or_insert_with_key` was unavailable.

As a somewhat-related note, this implements rust-lang/rfcs#1202 from 2015, so if this pull request is accepted, that should be closed.
@KodrAus
Copy link
Contributor

KodrAus commented Jul 29, 2020

As per rust-lang/rust#70996, we now have an unstable implementation of this in std, so I'll go ahead and close this issue now.

@KodrAus KodrAus closed this as completed Jul 29, 2020
@ChaiTRex
Copy link

Note: Fully stabilized today in Rust 1.50 in HashMap and in BTreeMap.

@ChaiTRex
Copy link

Stabilized in 1.50.0. See the method's documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-libs-api Relevant to the library API team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests

6 participants