There's some conflation going on with the terminology from another language, and I'm not sure where it's coming from (your own experience or the guide you're working through).
Rust has generics, not templates. Things like T
are generic type parameters, not template arguments.
Type parameters are not always references either. And what a reference is in Rust may not correspond to what references are in other languages, as well. Rust references are fully realized types that are somewhat like C pointers with more guarantees (non-null, always point at a valid value, compile-time borrow checking...)
So maybe T = String
, or maybe T = &String
. Both can happen and they're not the same thing, because String
and &String
are not the same type.
Also take care not to conflate the liveness scope of values with the Rust terminology around "lifetimes". The T: 'static
bound means "T
doesn't have any (non-'static
) borrows." It does not mean "values of type T
are never dropped."
String: 'static
for example, but String
s get drop and deallocate their memory, etc.
Types can also not satisfy a 'static
bound but still have destructors that run when dropped.
The term "owned type" can be confusing because it is sometimes meant as "a type that satisfies a 'static
bound", or sometimes even just "not a reference". But "ownership" is also used to mean "you're responsible for dropping the object"; a type "owning" another can mean the other type is a field of the "owning type", and so on.
It's hard to talk about what takes ownership and what owns what without some agreement on the terms being used. I'm going to use the concept of "those responsible for dropping are the owners".
Let's consider a concrete example:
fn foo<'g>(guard: MutexGuard<'g, String>) {}
What does foo
"take ownership" of? Unless it passes it somewhere else, it takes ownership of the MutexGuard
. At the end of foo
, the guard will be dropped which will release a lock on the borrowed Mutex
. But note that the MutexGuard
doesn't satisfy a 'static
bound -- it contains a borrow of the underlying Mutex
, which is how it is able to unlock it when dropped.
No ownership of a Mutex
or String
was passed, though.
Where things drop is tracked at compile time to some extent, but it's an undecidable problem generally, so there are also some runtime flags.
fn foo<'g>(guard: MutexGuard<'g, String>) {
if some_runtime_condition(&guard) {
drop(guard);
}
do_a_bunch_of_other_stuff();
// `guard` will drop here... unless it was already dropped above
}
In contrast, lifetimes are used for compile time analysis only, and don't change how code compiles (just what code can compile).
How about here?
fn bar<'s>(s: &'s mut String) {}
bar
wasn't passed ownship of a String
, but it was passed ownership of a &mut String
. Dropping an exclusive reference is a no-op however, and references (shared (&
) or exclusive (&mut
)) are the foundation of borrowing things in Rust, so it wouldn't be surprising for someone to say "bar
doesn't take ownership". Implicit in that phrasing is that the String
is the important part, and that it's not important that bar
takes ownership of a &mut String
.
But it can be a bit fuzzier with generics. Consider here:
fn takes_t<T>(t: T) {}
fn takes_ref_to_t<T>(t: &T) {}
We could say "takes_t
takes ownership (of T
) and takes_ref_to_t
doesn't take ownership (of T
)". But it's still the case that takes_ref_to_t
"takes ownership of a &T
".
...and then if we make some calls like so...
let s = String::new();
takes_t(&s);
takes_t(s);
In the first call, we have T = &String
, and takes_t
takes ownership of the &String
(but not a String
).
In the second call, we have T = String
and takes_t
takes ownership of the String
.
A Box
has exclusive ownership of what is inside, so if you coerce something into a Box<dyn Display>
by putting it in a Box
and type erasing it, the Box
will own the dyn Display
(which is the type-erased version of the original value). When the Box
drops, it will drop the dyn Display
, which will recursively drop the type-erased value.
This is true for a Box<dyn Display + 'static>
but also for any other lifetime. It's true for values you erase that have destructors, but also true for those which do not, like references.
You can create a Box<dyn Display + 'static
by boxing up a String
, and dropping the Box
will drop the String
, for example.
Or you can create a Box<dyn Display + '_>
by boxing up a &String
and dropping the Box
will drop the &String
-- which a no-op, but that's fine.