Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

참고:

'static 상수