Static
Rust에는 몇 가지 예약된 라이프타임 이름이 있습니다. 그중 하나가 'static입니다. 두 가지 상황에서 이를 마주칠 수 있습니다:
// 'static 라이프타임을 가진 참조:
let s: &'static str = "안녕 세상";
// 트레이트 바운드의 일부로서의 'static:
fn generic<T>(x: T) where T: 'static {}
두 가지는 관련이 있지만 미묘하게 다르며, 이는 Rust를 배울 때 흔한 혼란의 원인이 됩니다. 각 상황에 대한 몇 가지 예시를 소개합니다:
참조 라이프타임
참조 라이프타임으로서 'static은 참조가 가리키는 데이터가 실행 중인 프로그램의 남은 수명 동안 살아있음을 나타냅니다. 여전히 더 짧은 라이프타임으로 강제 변환될 수 있습니다.
'static 라이프타임을 가진 변수를 만드는 두 가지 일반적인 방법이 있으며, 둘 다 바이너리의 읽기 전용 메모리에 저장됩니다:
static선언으로 상수를 만듭니다.&'static str타입을 갖는문자열리터럴을 만듭니다.
각 방법에 대한 예제는 다음을 참조하세요:
// `'static` 라이프타임을 가진 상수를 만듭니다.
static NUM: i32 = 18;
// `NUM`에 대한 참조를 반환합니다. 여기서 `NUM`의 `'static`
// 라이프타임은 입력 인자의 라이프타임으로 강제 변환됩니다.
fn coerce_static<'a>(_: &'a i32) -> &'a i32 {
&NUM
}
fn main() {
{
// `문자열` 리터럴을 만들고 출력합니다:
let static_string = "저는 읽기 전용 메모리에 있습니다";
println!("static_string: {}", static_string);
// `static_string`이 스코프를 벗어나면, 참조는
// 더 이상 사용할 수 없지만, 데이터는 바이너리에 남아 있습니다.
}
{
// `coerce_static`에 사용할 정수를 만듭니다:
let lifetime_num = 9;
// `NUM`을 `lifetime_num`의 라이프타임으로 강제 변환합니다:
let coerced_static = coerce_static(&lifetime_num);
println!("강제 변환된 static: {}", coerced_static);
}
println!("NUM: {} 여전히 접근 가능합니다!", 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)
}
트레이트 바운드
트레이트 바운드로서, 이는 해당 타입이 정적이지 않은(non-static) 참조를 포함하지 않음을 의미합니다. 예를 들어, 수신자는 원하는 만큼 해당 타입을 보유할 수 있으며, 드롭할 때까지 절대 유효하지 않게 되지 않습니다.
이것이 의미하는 바를 이해하는 것이 중요합니다. 모든 소유된 데이터는 항상 'static 라이프타임 바운드를 통과하지만, 소유된 데이터에 대한 참조는 일반적으로 그렇지 않습니다:
use std::fmt::Debug;
fn print_it(input: impl Debug + 'static) {
println!("'static 값이 전달되었습니다: {:?}", input);
}
fn main() {
// i는 소유된 데이터이며 참조를 포함하지 않으므로 'static입니다:
let i = 5;
print_it(i);
// 이런, &i는 main()의 스코프에 의해 정의된 라이프타임만
// 가지므로 '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