Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite section on 'static lifetime. #1320

Merged
merged 1 commit into from
Mar 29, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 69 additions & 9 deletions src/scope/lifetime/static_lifetime.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
# Static

A `'static` lifetime is the longest possible lifetime, and lasts for
the lifetime of the running program. A `'static` lifetime may also be
coerced to a shorter lifetime. There are two ways to make a variable
with `'static` lifetime, and both are stored in the read-only memory
of the binary:
Rust has a few reserved lifetime names. One of those is `'static`. You
might encounter it in two situations:

```rust, editable
// A reference with 'static lifetime:
let s: &'static str = "hello world";

// 'static as part of a trait bound:
fn generic<T>(x: T) where T: 'static {}
```

Both are related but subtly different and this is a common source for
confusion when learning Rust. Here are some examples for each situation:

## Reference lifetime

As a reference lifetime `'static` indicates that the data pointed to by
the reference lives for the entire lifetime of the running program.
It can still be coerced to a shorter lifetime.

There are two ways to make a variable with `'static` lifetime, and both
are stored in the read-only memory of the binary:

* Make a constant with the `static` declaration.
* Make a `string` literal which has type: `&'static str`.
Expand All @@ -15,7 +32,7 @@ See the following example for a display of each method:
// Make a constant with `'static` lifetime.
static NUM: i32 = 18;

// Returns a reference to `NUM` where its `'static`
// Returns a reference to `NUM` where its `'static`
// lifetime is coerced to that of the input argument.
fn coerce_static<'a>(_: &'a i32) -> &'a i32 {
&NUM
Expand All @@ -30,7 +47,7 @@ fn main() {
// When `static_string` goes out of scope, the reference
// can no longer be used, but the data remains in the binary.
}

{
// Make an integer to use for `coerce_static`:
let lifetime_num = 9;
Expand All @@ -40,13 +57,56 @@ fn main() {

println!("coerced_static: {}", coerced_static);
}

println!("NUM: {} stays accessible!", NUM);
}
```

## Trait bound

As a trait bound, it means the type does not contain any non-static
references. Eg. the receiver can hold on to the type for as long as
they want and it will never become invalid until they drop it.

It's important to understand this means that any owned data always passes
a `'static` lifetime bound, but a reference to that owned data generally
does not:

```rust,editable,compile_fail
use std::fmt::Debug;

fn print_it( input: impl Debug + 'static )
{
println!( "'static value passed in is: {:?}", input );
}

fn use_it()
{
// i is owned and contains no references, thus it's 'static:
let i = 5;
print_it(i);

// oops, &i only has the lifetime defined by the scope of
// use_it(), so it's not 'static:
print_it(&i);
}
```
The compiler will tell you:
```ignore
error[E0597]: `i` does not live long enough
--> src/lib.rs:15:15
|
15 | print_it(&i);
| ---------^^--
| | |
| | borrowed value does not live long enough
| argument requires that `i` is borrowed for `'static`
16 | }
| - `i` dropped here while still borrowed
```

### See also:

[`'static` constants][static_const]

[static_const]: ../../custom_types/constants.md
[static_const]: ../../custom_types/constants.md