3 ms·
The first one creates an implied bound, while the second is an explicit bound. The important thing about implied bounds is that they allow late binding of lifet
by LegionMammal978 3y ago
The first one creates an implied bound, while the second is an explicit bound. The important thing about implied bounds is that they allow late binding of lifetimes to function pointers (or closures): that is, you can have a single function pointer type like "for<'a> fn(&'a str)" that can be called with any lifetime 'a. Here, the lifetime 'a is called "late-bound", since it can be different with each call.
In contrast, if a lifetime is subject to an explicit where bound, it must be "early-bound": each function pointer can must choose one particular value for that lifetime, that must be upheld for every call. For a practical example, you might have tried to declare a closure with a &T parameter, only to get lifetime errors when you call it twice. This is because the lifetime in the closure type is early-bound and must be the same for every call. (Sometimes the compiler figures out that a late-bound lifetime is desired, but the rules are very subtle. This is also why it's difficult to write a function that accepts a generic async closure.)
Late binding is necessary for certain kinds of variance, which is a big part of this issue. Function pointers are contravariant in their parameters, which means if you have a type like "fn(&'short str)", you can cast it to "fn(&'static str)", since a 'static reference will always be valid for 'short. They're also covariant in their return type, so that "fn() -> &'static str" can be cast into "fn() -> &'short str". But when performing these variance transformations with late-bound lifetimes, the compiler doesn't always take into account the implied bounds in the source type properly, which allows you to perform casts that aren't actually sound.