What I think the difference might be: the second function allows the caller to pick a lifetime shorter than 'static... however I'm not sure if that makes a meaningful difference since doesn't a 'static lifetime automatically coerce into shorter ones when necessary? So can't the first function be used for the same purpose?
So if I understand correctly, a 'static is always better than an 'a in practice (since 'static is a subtype of any 'a) but when I'm working with some T I can design a more flexible function interface if I bind T by 'a instead of 'static?
This is too many levels of abstraction deep for me to fully process. Could I see a concrete example of where a "dangling" lifetime would be preferably used over a 'static lifetime?
Or wait, lemme try myself first:
fn main() {
let a = 10;
let boxed_a_ref = Box::new(&a);
// this would not compile if
// `fn leak(self) -> &'static mut T where T: 'static`
// right?
// it only works because
// `fn leak(self) -> &'a mut T where T: 'a`
// ?
let leaked_a_ref = Box::leak(boxed_a_ref);
}
Sort of, a dangling lifetime is usually better, but sometimes it's too verbose for no gain. It's always at least as flexible as 'static, because 'static will be inferred if there are no other constraints.
Sorry to bump this kinda old-ish thread but I finally found an answer for this question. A reader originally raised this issue on my blog which unfortunately shows that there is indeed a difference between how for<'a, T> fn() -> &'a T and for<T> fn() -> &'static T can be used in practice. I've updated my article with a new section to describe the difference. I'll import the answer here anyway.
This compiles:
use rand;
fn generic_str_fn<'a>() -> &'a str {
"str"
}
fn static_str_fn() -> &'static str {
"str"
}
fn a_or_b<T>(a: T, b: T) -> T {
if rand::random() {
a
} else {
b
}
}
fn main() {
let some_string = "string".to_owned();
let some_str = &some_string[..];
let str_ref = a_or_b(some_str, generic_str_fn()); // compiles
let str_ref = a_or_b(some_str, static_str_fn()); // compiles
}
This does not:
use rand;
fn generic_str_fn<'a>() -> &'a str {
"str"
}
fn static_str_fn() -> &'static str {
"str"
}
fn a_or_b_fn<T, F>(a: T, b_fn: F) -> T
where F: Fn() -> T
{
if rand::random() {
a
} else {
b_fn()
}
}
fn main() {
let some_string = "string".to_owned();
let some_str = &some_string[..];
let str_ref = a_or_b_fn(some_str, generic_str_fn); // compiles
let str_ref = a_or_b_fn(some_str, static_str_fn); // compile error
}
A more concise example that also does not compile:
Rust can coerce &'static T into &'a T since they are values. Rust cannot coerce for<T> fn() -> &'static T into for<'a, T> fn() -> &'a T since they are types. They key takeaway here I believe is to prefer using the latter since it's more flexible and can be used in more scenarios.