`impl Trait` inside a trait

How can I write this in stable (or even unstable) Rust?

pub trait Queryable<B, D> {
    fn query<'a, Q: Query<B> + 'a>(&'a self, query: Q) -> impl Iterator<Item = (ID, &'a D)> + 'a;
}
  • If impl Trait in traits existed then this would just work.
  • If GAT existed then an associated type would work.
  • HRTB almost works, but it then I can't get the Iterator type to depend on the query type.

I'm always very cautious around lifetime parameters on traits, but maybe this is a case where it's necessary? FWIW, this compiles:

use std::collections::HashMap;

pub trait Query {}

#[derive(PartialEq, Eq, Hash)]
pub struct ID;

pub trait Queryable<'a, D: 'a> {
    type QueryIter: 'a + Iterator<Item = (&'a ID, &'a D)>;
    
    fn query<Q: Query + 'a>(&'a self, query: Q) -> Self::QueryIter;
}

impl<'a, D: 'a> Queryable<'a, D> for HashMap<ID, D> {
    type QueryIter = std::collections::hash_map::Iter<'a, ID, D>;
    
    fn query<Q: Query + 'a>(&'a self, query: Q) -> Self::QueryIter {
        self.iter()
    }
}

(Playground link)

Perhaps not how you wanted it to look, but instead you might be able to box it up?
Playground

Yeah, I'm boxing it for now and it works.

@troiganto: That almost works, except where you want the type QueryIter to depend on the type Q (which is very common), in which case you need GATs.

2 Likes