Hi!
Been writing some functions which forward their arguments to HashMap. The problem is, I need to write tons of 'where' constraints just to pass some value as hash map's key. So I tried to wrote someting like this:
trait HashKeyable<K> {}
impl<T: ?Sized, K> HashKeyable<K> for T
where T: Hash + Eq, K: Borrow<T>
{ }
and then (assuming hash-map is keyed with strings)
fn map_accessor<Q: HashKeyable<String>>(&self, k: &Q) -> SomeValue {
self.table[k]
}
The problem is, compiler complains that Q doesn't conform to ?Sized + Hash + Eq, where it should.
Any ideas how to do it properly?
Thanks
llogiq
September 2, 2015, 12:04pm
2
Sorry, but the trait bounds have to be repeated every time. A nicer solution is to use associated types for the key and value type.
1 Like
The following compiles:
use std::collections::HashMap;
use std::borrow::Borrow;
use std::hash::Hash;
trait HashComparable : Eq + Hash {}
impl<T: ?Sized + Hash + Eq> HashComparable for T { }
trait HashKeyable<K: ?Sized + Eq + Hash> : Borrow<K> + Hash + Eq {}
impl<K: ?Sized + Eq + Hash, T: ?Sized + Borrow<K> + Hash + Eq> HashKeyable<K> for T { }
fn map_accessor<'a, Q: ?Sized + HashComparable, T: HashKeyable<Q>>(h: &'a HashMap<T, String>, k: &Q) -> &'a str {
&h[k]
}
fn main() {
let mut s = HashMap::new();
s.insert("asdf".to_owned(), "zxcv".to_owned());
println!("{}", map_accessor(&s, "asdf"));
}
Maybe not exactly what you were trying to do? Anyway, the trick is that you have to put the bounds on both the trait and the implementation.