Lifetime problem: generic fields iterator

Hello. Another lifetime problem in generics I struggle to solve. I use, but don't understand associated types of such kind

type Key<'k> where Self: 'k;

What does it say and why is it necessary to use here? Appreciate help.

Iā€™m not sure why this happens or if it applies to every case, but this solution fixes the problem. Maybe someone can explain why?

Borrowed:  'static

Why this bound must be applied and why is not it obstacle for compiler to compile?

bounds on associated types are exactly the same as bounds on any other type.

T: 'static implies T: 'a for all possible 'a, since 'static is the longest possible lifetime.

However, it probably makes no sense for a borrowed type to require 'static because it will then become useless (it can't then contain any temporary references, only 'static references, or no references at all ā€“ effectively, it'll become an owned type, not a borrowed one).

1 Like

Hello. Thanks for answer. But why does it compile and work with 'static?

Again, because Borrowed: 'static satisfies the requirement Borrowed: 'v (no matter what 'v is).

1 Like

I'm confused because I don't understand why then it's allowed for parameter Borrowed to be types having references... :thinking:

The immediate source of the error in the OP playground is that Self: 'a + Borrow<Borrowed> doesn't imply Borrowed: 'a. There are ways around it -- at least to some extent -- if you make your trait specific to one lifetime. But I don't know if it's worth it for your use case. If you don't care about Vec<BorrowedThings>, maybe the 'static workaround will be enough for you.

(I'll write it up if you want, but it may just lead you down some convoluted path you don't need.)


Incidentally what to the parameters K and V represent here?

pub trait Fields<K, V> {
    type Key<'k> where Self: 'k;
    type Val<'v> where Self: 'v;
    fn fields(&self) -> impl IteratorTrait<Item = (Self::Key<'_>, Self::Val<'_>)>;
}

It can't be "implementor is a collection mapping K to V", because that's not what you have attempted to implement:

//   different types            vvvvvvvvv          v
impl<V, Borrowed> Fields<usize, &Borrowed> for Vec<V>

And it can't be "thing you want to iterate over", based on the signature of the method -- that's Val<'_>.

    fn fields(&self) -> impl IteratorTrait<
        Item = (Self::Key<'_>, Self::Val<'_>)
    >;

Is it just some sort of marker so you can have multiple implementations for the same type (Vec<V>)?

Asking because it's hard to give advice without understanding the design (or XY goal).

2 Likes

Hello. I see.

And it can't be "thing you want to iterate over", based on the signature of the method -- that's Val<'_>.

That's right.

Is it just some sort of marker so you can have multiple implementations for the same type (Vec<V>)?

Not marker, Key for key and Val for value.
Purpose of trait Fields to iterate over fields convertible to a specified type within an entity. Both key and val are parameters and same entity could have several Fields implemented for it.

f you don't care about Vec<BorrowedThings>, maybe the 'static workaround will be enough for you.

But currently Vec<BorrowedThings> works.

fn test(a: &str, b: &str) {
    let collection: Vec<&str> = vec![a, b];
    let got: Vec<(usize, &str)> = Fields::<usize, &str>::fields(&collection).collect();
    assert_eq!(got.len(), 2);
}

Or I misunderstand something? Is not that Vec<BorrowedThings>?

I didn't forget about this but haven't had time to circle back. (I believe I made some mental misstep and something I didn't think would work, does work.) I'll try to come back to it again later.

1 Like

Maybe it's a bug of compiler?

I don't think there's a bug here.

it's never a compiler bug.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.