Note that structs with lifetimes are often a bad idea. Not just because they clutter your code with lifetime annotations, but because they severely limit how you can use these types .
My recommendation is to think really carefully before adding a lifetime to a struct. When in doubt, use an owned type ( String instead of &str , Box<dyn Foo> instead of &dyn Foo , etc.).
When used with multiple lifetimes 'self loses any special meaning it could have had. If we were to go in that direction (I'm not saying we shouldn't), I'd prefer to have something more related to introducing unnamed free variables lifetime parameters:
'a is not the lifetime of App<'a>. It is also not the lifetime of Handle<'a>. To say it is betrays a fundamental misunderstanding of lifetimes.
'a is an upper bound on how long you can hold a Handle<'a>. 'a is the lifetime of some borrow which Handle<'a> depends on. Handle<'a> must be dropped before the end of 'a, but 'a may extend far after Handle<'a> may be dropped (and before the Handle<'a> is created).
IIUC, these only impact how the lifetime may change (e.g. if you can interpret &Handle<'a> as &Handle<'b> where 'a > 'b). Also, the only contravariance we have in Rust is the T in fn(T) -> _. Contravariance is such a tiny detail that it's much easier to ignore it until it's actually a problem. Personally, I always make it obvious by doing for<'f: 'a> fn(&'f _) rather than fn(&'a _). Also, if 'a is unbound, it should be for<'a> anyway.
In any case, when talking about the drop timing of a value and the lifetime it captures, variance doesn't even really come in to the picture, as it's only the one interpretation of the value we care about.
You can think about it like this: it's always legal when you own a value to break it into its fields (modulo privacy and drop impls). This ends the region that App<'c> exists, but does nothing to the borrow region that App<'c> is contained within.
The lifetime 'c is (maximally) a name for the region from when the borrow was created to when the borrow is no longer valid. App<'c> must exist within this region, but nothing says it must exist for the entire region.
Variance allows you to use arbitrarily shorter regions within the defining region, but either that new name is bound to an actual defined region, or it "floats", having multiple possible end timings, of which typically the most convenient is chosen (until further restricted). Also, most lifetimes are floating, as they float as soon as it's in a non-invariant holder and passed between storage spaces (assigned to a new variable or passed to a function).
I have a library, generativity, that actually creates an instance of a type that "unique"ly defines a new invariant lifetime that is defined as from its creation to its drop. It's complicated how it does so, and it requires a decent amount of macro trickery to make sure it's sound. (It's only "unique" among lifetimes generated by this technique; other "floating" lifetimes are free to shorten to equal it.)
And actually, even in generativity, which goes out of its way to guarantee that the lifetime is as close to the region the struct make_guard<'id> is live, extends beyond that region. Read the readme for more gritty details, but the 'id lifetime begins "shortly before" the make_guard and dies "shortly after", definitely not at the same time.
What would you use it for? There are a few use cases, which can currently be addressed with PhanthomData, but I'm intrigued which case you've hit that you want to address.
I mean during development I cannot know the best solution and I can use later references inside of structure or will remove it after some iterations of development