3

I have a HashMap with Option<String> keys; is it possible to do lookups with a key of type Option<&str>? I know I can use a &str to lookup in a HashMap<String, V> because str implements Borrow<String>.

Do I have to convert to an owned string just to do a lookup?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Twan van Laarhoven
  • 2,542
  • 15
  • 16
  • 1
    Does this answer your question? [How do I use the Entry API with an expensive key that is only constructed if the Entry is Vacant?](https://stackoverflow.com/questions/51542024/how-do-i-use-the-entry-api-with-an-expensive-key-that-is-only-constructed-if-the) – Stargateur Nov 07 '20 at 10:15
  • The Entry api is for optionally adding a key to the map, I am only talking about lookups. – Twan van Laarhoven Nov 11 '20 at 20:00
  • for the last time duplicate is about answer not question read the answer not the question *- - – Stargateur Nov 11 '20 at 22:41
  • With the raw entry api, the only solution I can think of is to use `map.raw_entry().from_hash(somehow_calculate_a_hash(key), |k| k.as_ref() == key)`. – Twan van Laarhoven Nov 12 '20 at 19:58
  • no where in the thread I link to you there is write `from_hash()`. I can't read for you. – Stargateur Nov 12 '20 at 20:06
  • Nowhere in that thread is a direct answer to my question. I assumed that you meant that I should use the raw_entry API as is suggested in the accepted answer for that question. If that is not what you meant, then what did you mean? – Twan van Laarhoven Nov 12 '20 at 20:10
  • https://play.integer32.com/?version=nightly&mode=debug&edition=2018&gist=82f51e3bf8a0f73a0636436b8005734c, doesn't seem to be possible with Option, anyway have an Option as key in a Hashmap don't make sense – Stargateur Nov 12 '20 at 20:18

1 Answers1

1

It's slightly less efficient, but you could use Cow here. It avoids the problem with the Borrow trait by instead having a single type that can represent either a reference or an owned value, like so:

use std::borrow::Cow;
use std::collections::HashMap;

fn main() {
    let mut map = HashMap::<Option<Cow<'static, str>>, i32>::new();
    map.insert(None, 5);
    map.insert(Some(Cow::Borrowed("hello")), 10);
    map.insert(Some(Cow::Borrowed("world")), 15);
    
    // works with None and constant string slices...
    assert_eq!(map.get(&None), Some(&5));
    assert_eq!(map.get(&Some(Cow::Borrowed("hello"))), Some(&10));
    
    // ...and also works with heap-allocated strings, without copies
    let stack = String::from("world");
    assert_eq!(map.get(&Some(Cow::Borrowed(&stack))), Some(&15));
}
apetranzilla
  • 5,331
  • 27
  • 34