I'm trying to write a trait that builds a struct from borrows of the fields of the implmenter, e.g.
// pseudo code
// error handling omitted for brevity
trait Collector {
type Key;
type Collection: 'a; // would require to add 'a to trait signature
// but lifetime depends on borrow instead of implementer
fn collect<'a>(&'a self, key: &Self::Key) -> Self::Collection<'a>
}
struct Example {
values: Vec<u32>
}
impl Collector for Example {
type Key = (usize, usize);
type Collection = (&'a u32, &'a u32); // Here the problem is obvious
fn collect<'a>(&'a self, key: &Self::Key) -> Self::Collection<'a> {
(&self.values[key.0], &self.values[key.1])
}
}
As you can see my proble is that my assosiated type requires a lifetime but this lifetime originates from the method call not from trait implementation.
I tried a bit with higher-kinded-lifetimes (i.e. for<'a>) but I don't realy figure out how to use these.
Well, that would be a solution but I have two problems with that:
This adds a lifetime to the trait so my code gets spoiled with lifetimes everywhere.
The trait's lifetime expresses wrong semantics. If a trait has a lifetime-parameter it suggests that the implementer holds some reference, meaning that the lifetime is at least as long as the implementer's. But the lifetime I want to express is only for the Collection I produce.
An example: When collect() is called the Collection must live as long as the Collector. This means I can no longer end the borrow of Collector by dropping the Collection because they have the same lifetime. As a result Collector can not be mutated after the first call of collect() even if the Collection is no longer in use!
Therefore, I want the lifetime tied to the Collection rather than the Collector.
BTW: I know this could be easily done with GATs but... well.. we all know...
Ok, I see you're right . My actual use case is way more complicated and I'm using values of the Collection as Keys for further querying of the Collector, seemingly I have some very specific case that can't be reproduced by such a simple example.
Nevertheless, I solved the problem myself by removing the assosiate Collection. I had only two of them and now I have two Collector-traits either. This is not very nice but works until we have GATs...