Reference types
Let’s open with a question: is &str a type?
When not being pedantic or formal, pretty much everyone will say yes, &str is a type.
However, it is technically a type constructor which is parameterized with a generic
lifetime parameter. So &str isn’t technically a type, &'a str for some concrete
lifetime is a type. &'a str and &'b str are not the same type, unless 'a == 'b.
Similarly, Vec<T> for a generic T is a type constructor, but Vec<i32> is a type.
Vec<T> and Vec<U> are not the same type, unless T == U.
There is no single Vec type for all possible contents, and there is no single &str
type for all possible lifetimes.
By “concrete lifetime”, I mean some compile-time determined lifetime. The exact
definition of “lifetimes” in Rust is surprisingly complicated and beyond the scope
of this guide, but here are a few examples of &strs and their concrete types.
#![allow(unused)]
fn main() {
// The exact lifetime of `'a` is determined at each call site. We'll explore
// what this means in more depth later.
//
// The lifetime of `b` works the same, we just didn't give it a name.
fn example<'a>(a: &'a str, b: &str) {
// Literal strings are `&'static str`
let s = "literal";
// The lifetime of local borrows are determined by compiler analysis
// and have no names (but it's still a single lifetime).
let local = String::new();
let borrow = local.as_str();
// These are the same and they just tell the compiler to infer the
// lifetime. In this small example that means the same thing as not
// having a type annotation at all.
let borrow: &str = local.as_str();
let borrow: &'_ str = local.as_str();
}
}