Just as here
fn foo() -> &'static str { "hi" }
fn main() {
s = foo();
}
the returned &'static str
can be coerced to an arbitrarily shorter lifetime (due to covariance), here
fn foo<'a>() -> &'a str { "hi" }
The literal "hi"
is const promoted to a &'static str
which can then be coerced to an arbitrarily shorter lifetime.
It probably wasn't technically inferred to be 'static
, it was probably inferred to be a lifetime that ended at the end of the statement. But a higher-level view is that it doesn't matter what it was inferred to be exactly -- it was inferred to be a lifetime that upheld soundness (and then that lifetime was erased by runtime).
The example does illustrate again that returning &'static
is adequate for covariant types. It does mean that foo::<'non_static_lifetime>
isn't a function item type. Though that's a pretty niche consideration.
Output lifetime can't be late bound like that in the current compiler, though that may change in the future.
(Late-bound is a mostly internal concept, but the short gist of it is that if the lifetime isn't generic on the type of the function, then you can't
impl<'a> Fn() -> &'a str for TheFunction { /* ... */ }
// unsugared, nightly
impl<'a> Fn(()) for TheFunction {
type Output = &'a str;
// ...
}
similar to how you can't, say,
struct Iter;
impl<'a> Iterator for Iter {
type Item = &'a str;
fn next() -> Option<Self::Item> {
None
}
}
)
It could be an early bound yet anonymous lifetime I suppose; I think argument-position impl Trait
works that way for types now.
Whether there's enough motivation to do so is another question. Returning a lifetime out of nowhere just isn't that common of a legitimate pattern.