Blanket constraint traits?


#1

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


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


#3

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.