Joe Neeman
Joe Neeman

Reputation: 173

String-keyed HashMap in rust?

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?

Upvotes: 7

Views: 9729

Answers (2)

Chris Morgan
Chris Morgan

Reputation: 90892

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.)

Upvotes: 4

huon
huon

Reputation: 102296

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.)

Upvotes: 3

Related Questions