2

I have a generic struct in Rust and want the parameter K to have some trait bounds like so:

pub struct IndexStore<K, V>
where
    K: std::cmp::Eq + Hash + Debug,
{
    m: HashMap<K, V>,
    name: Option<String>,
}

But now, whenever I write an impl block I find myself needing to write the trait bound out again. If not I get errors like "the trait bound K: std::cmp::Eq is not satisfied". Here are some examples of my impl blocks:


impl<K, V> Deref for IndexStore<K, V>
where
    K: std::cmp::Eq + Hash + Debug,
{
    type Target = HashMap<K, V>;

    fn deref(&self) -> &Self::Target {
        &self.m
    }
}

impl<K, V> DerefMut for IndexStore<K, V>
where
    K: std::cmp::Eq + Hash + Debug,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.m
    }
}

impl<K, V> FromIterator<(K, V)> for IndexStore<K, V>
where
    K: std::cmp::Eq + Hash + Debug,
{
    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
        IndexStore {
            m: iter.into_iter().collect(),
            name: None,
        }
    }
}

How can I only specify the trait bound once in the struct definition without repeating it in every impl block?

Tadeo Hepperle
  • 550
  • 2
  • 12

1 Answers1

4

This is RFC 2089, "Extended implied bounds" however it is not yet implemented, and it is not clear what will be the shape of the feature.

However, you should not put bounds on the struct unless the struct will not compile without them, so this is likely not a good idea anyway.

On nightly, you can use a trait alias to shorten the bound:

#![feature(trait_alias)]

trait EqHashDebug = std::cmp::Eq + std::hash::Hash + std::fmt::Debug;

pub struct IndexStore<K, V> {
    m: HashMap<K, V>,
    name: Option<String>,
}

impl<K: EqHashDebug, V> Deref for IndexStore<K, V> {
    type Target = HashMap<K, V>;

    fn deref(&self) -> &Self::Target {
        &self.m
    }
}

impl<K: EqHashDebug, V> DerefMut for IndexStore<K, V> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.m
    }
}

impl<K: EqHashDebug, V> FromIterator<(K, V)> for IndexStore<K, V> {
    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
        IndexStore {
            m: iter.into_iter().collect(),
            name: None,
        }
    }
}

On stable, you can emulate a trait alias with a trait with a a blanket implementation:

trait EqHashDebug: std::cmp::Eq + std::hash::Hash + std::fmt::Debug {}
impl<T: ?Sized + std::cmp::Eq + std::hash::Hash + std::fmt::Debug> EqHashDebug for T {}
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77