Static
У Rust є кілька зарезервованих назв часів життя. Одна з них — 'static. Ви
можете натрапити на неї у двох ситуаціях:
// 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 {}
Обидва випадки пов’язані, але дещо різняться, і це поширене джерело плутанини під час вивчення Rust. Ось кілька прикладів для кожної ситуації:
Reference lifetime
Як час життя посилання 'static означає, що дані, на які вказує
посилання, живуть протягом решти часу життя виконуваної програми.
Його все ще можна привести до коротшого часу життя.
Існує два поширені способи створити змінну з часом життя 'static, і обидва
зберігаються в пам’яті лише для читання бінарного файлу:
- Створити константу за допомогою оголошення
static. - Створити рядковий літерал, який має тип:
&'static str.
Дивіться наступний приклад, де показано кожен метод:
// Make a constant with `'static` lifetime.
static NUM: i32 = 18;
// 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
}
fn main() {
{
// Make a `string` literal and print it:
let static_string = "I'm in read-only memory";
println!("static_string: {}", static_string);
// 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;
// Coerce `NUM` to lifetime of `lifetime_num`:
let coerced_static = coerce_static(&lifetime_num);
println!("coerced_static: {}", coerced_static);
}
println!("NUM: {} stays accessible!", NUM);
}
Оскільки посилання 'static мають бути дійсними лише протягом решти життя
програми, їх можна створити під час виконання програми. Щоб це
показати, приклад нижче використовує
Box::leak
для динамічного створення посилань 'static. У цьому випадку вони точно не
живуть протягом усього часу, а лише від точки витоку далі.
extern crate rand;
use rand::Fill;
fn random_vec() -> &'static [u64; 100] {
let mut rng = rand::rng();
let mut boxed = Box::new([0; 100]);
boxed.fill(&mut rng);
Box::leak(boxed)
}
fn main() {
let first: &'static [u64; 100] = random_vec();
let second: &'static [u64; 100] = random_vec();
assert_ne!(first, second)
}
Trait bound
Як обмеження трейтів, це означає, що тип не містить жодних не-static посилань. Наприклад, одержувач може тримати цей тип стільки, скільки захоче, і він ніколи не стане недійсним, доки його не буде звільнено.
Важливо розуміти, що це означає: будь-які власні дані завжди задовольняють
обмеження часу життя 'static, але посилання на ці власні дані зазвичай —
ні:
use std::fmt::Debug;
fn print_it(input: impl Debug + 'static) {
println!("'static value passed in is: {:?}", input);
}
fn main() {
// 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
// main(), so it's not 'static:
print_it(&i);
}
Компілятор повідомить вам:
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