Files
100-exercises-to-learn-rust/book/src/07_threads/02_static.md
Luca Palmieri 96f06708b0 Render the book in PDF using pandoc and LaTeX. (#126)
* Render the book in PDF using `pandoc` and LaTeX.

* Fix installs.

* Go the apt-get route

* Another attempt

* Avoid installing twice.

* Re-order.

* Add more packages.

* Minimise deps. Fix link checker.

* Missing package.

* Missing package.

* Missing package.

* More packages.

* Missing package.

* Missing package.

* More packages...

* Remove.

* Fix link checker.

* Fix link checker.

* Fix path.

* Add subtitle.

* Avoid running over the right margin.

* Avoid running over the right margin.

* Formatting
2024-08-05 17:52:15 +02:00

115 lines
3.4 KiB
Markdown

# `'static`
If you tried to borrow a slice from the vector in the previous exercise,
you probably got a compiler error that looks something like this:
```text
error[E0597]: `v` does not live long enough
|
11 | pub fn sum(v: Vec<i32>) -> i32 {
| - binding `v` declared here
...
15 | let right = &v[split_point..];
| ^ borrowed value does not live long enough
16 | let left_handle = spawn(move || left.iter().sum::<i32>());
| --------------------------------
argument requires that `v` is borrowed for `'static`
19 | }
| - `v` dropped here while still borrowed
```
`argument requires that v is borrowed for 'static`, what does that mean?
The `'static` lifetime is a special lifetime in Rust.\
It means that the value will be valid for the entire duration of the program.
## Detached threads
A thread launched via `thread::spawn` can **outlive** the thread that spawned it.\
For example:
```rust
use std::thread;
fn f() {
thread::spawn(|| {
thread::spawn(|| {
loop {
thread::sleep(std::time::Duration::from_secs(1));
println!("Hello from the detached thread!");
}
});
});
}
```
In this example, the first spawned thread will in turn spawn
a child thread that prints a message every second.\
The first thread will then finish and exit. When that happens,
its child thread will **continue running** for as long as the
overall process is running.\
In Rust's lingo, we say that the child thread has **outlived**
its parent.
## `'static` lifetime
Since a spawned thread can:
- outlive the thread that spawned it (its parent thread)
- run until the program exits
it must not borrow any values that might be dropped before the program exits;
violating this constraint would expose us to a use-after-free bug.\
That's why `std::thread::spawn`'s signature requires that the closure passed to it
has the `'static` lifetime:
```rust
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static
{
// [..]
}
```
## `'static` is not (just) about references
All values in Rust have a lifetime, not just references.
In particular, a type that owns its data (like a `Vec` or a `String`)
satisfies the `'static` constraint: if you own it, you can keep working with it
for as long as you want, even after the function that originally created it
has returned.
You can thus interpret `'static` as a way to say:
- Give me an owned value
- Give me a reference that's valid for the entire duration of the program
The first approach is how you solved the issue in the previous exercise:
by allocating new vectors to hold the left and right parts of the original vector,
which were then moved into the spawned threads.
## `'static` references
Let's talk about the second case, references that are valid for the entire
duration of the program.
### Static data
The most common case is a reference to **static data**, such as string literals:
```rust
let s: &'static str = "Hello world!";
```
Since string literals are known at compile-time, Rust stores them _inside_ your executable,
in a region known as **read-only data segment**.
All references pointing to that region will therefore be valid for as long as
the program runs; they satisfy the `'static` contract.
## Further reading
- [The data segment](https://en.wikipedia.org/wiki/Data_segment)