7

I'm having trouble figuring out how to use a HashMap with a key of type ~str idiomatically. For example,

let mut map: hashmap::HashMap<~str, int> = hashmap::HashMap::new(); // Inserting is fine, I just have to copy the string. map.insert("hello".to_str(), 1); // If I look something up, do I really need to copy the string? // This works: map.contains_key(&"hello".to_str()); // This doesn't: as expected, I get // error: mismatched types: expected `&~str` but found `&'static str` (expected &-ptr but found &'static str) map.contains_key("hello"); 

Based on this bug report, I tried

map.contains_key_equiv("hello"); 

but got

error: mismatched types: expected `&<V367>` but found `&'static str` (expected &-ptr but found &'static str) 

I really don't understand this last message; does anyone have a suggestion?

1
  • This question is now obsolete; thanks to the Borrow trait, a simple translation of the code to current syntax and method names will work just fine, with no error. Commented Mar 31, 2019 at 8:54

2 Answers 2

4

You have HashMap<K, V> with ~str (an owned string) as K; thus, where it wants &K for things, that is &~str—a reference to an owned string. You, however, are passing it a reference to a static string (a string literal without any sigil [&, ~, etc.], "hello", is of type &'static str).

For string literals, do not use .to_str(); instead, prefix it with a ~, as ~"hello". A string literal like that is of type ~str. For a non-literal, you should typically use .to_owned() of a &str.

The eventual code can operate like this:

use std::hashmap::HashMap; fn main() { let mut h = HashMap::new::<~str, int>(); h.insert(~"foo", 42); printfln!("%?", h.find(&~"foo")); // => Some(&42) printfln!("%?", h.contains_key(&~"foo")); // => true // You don’t actually need the HashMap to own the keys (but // unless all keys are 'static, this will be likely to lead // to problems, so I don’t suggest you do it in reality) let mut h = HashMap::new::<&str, int>(); h.insert("foo", 42); printfln!("%?", h.find(& &"foo")); // => Some(&42) } 

Observe that when you need a reference to a reference you can't do && as that is the boolean AND operator; you need to do &(&x) or & &x.

(Note also that any issue from three months ago may not be current; I'm not certain of the current state of HashMap's comparison techniques—try both ways, with the correct types.)

Sign up to request clarification or add additional context in comments.

2 Comments

This is no longer accurate as of rust 1.0
Yep. The HashMap API is much nicer now, as get and contains_key can take a type that is equivalent to the key type thanks to Borrow, and so you can just h.get("foo") instead of the old h.find(&~"foo") which performed an unnecessary heap allocation. play.rust-lang.org/… is an update of the code sample to use current techniques. However, I’m disinclined to update the answer as a whole, because it’s for a question that simply isn’t relevant in current Rust, thanks to this Borrow trait.
3

The declaration of contains_key_equiv is:

pub fn contains_key_equiv<Q:Hash + Equiv<K>>(&self, key: &Q) -> bool 

That is, it takes a reference to something that is Equivalent to K == ~str. So to check for a &str (which is Equivalent to ~str), we want a & &str (a reference to a string slice).

map.contains_key_equiv(&("hello")); // or map.contains_key_equiv(& &"hello"); 

(Note that these are equivalent, and are just required to get around the fact that "foo" == &"foo" are both &strs.)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.