무제한 수명

불안전한 코드는 종종 허공에서 레퍼런스나 수명을 만들어내곤 합니다. 이런 수명들은 무제한의 상태로 세계에 들어오게 됩니다. 이것이 일어나는 가장 흔한 경로는 생 포인터를 역참조한 다음 그것의 레퍼런스를 취하는 것인데, 이것은 무제한의 수명을 가진 레퍼런스를 생산하게 됩니다. 이런 수명은 상황이 요구하는 만큼 범위가 커집니다. 이것은 사실 그냥 'static이 되는 것보다 더 강력한데, 예를 들어 &'static &'a T&'a &'a T와 타입이 맞지 않을 것이지만, 무제한의 수명은 필요하다면 완벽하게 &'a &'a T에 맞아들어갈 것이기 때문입니다. 그러나 대부분의 의도와 목적에서는, 이런 무제한의 수명은 'static으로 간주해도 됩니다.

'static인 레퍼런스는 거의 없으니, 이것은 아마 잘못된 것일 것입니다. transmutetransmute_copy는 이런 일이 일어날 수 있는 또다른 두 가지의 원인들입니다. 우리는 최선을 다해서, 가능한 한 빨리 무제한의 수명을 제한시켜야 합니다, 특히 함수 경계를 지날 때 말이죠.

함수가 주어졌을 때 입력들에서 파생되지 않는 출력 수명은 무제한이 됩니다. 예를 들면:

fn get_str<'a>(s: *const String) -> &'a str {
    unsafe { &*s }
}

fn main() {
    let soon_dropped = String::from("hello");
    let dangling = get_str(&soon_dropped);
    drop(soon_dropped);
    println!("잘못된 str: {}", dangling); // 잘못된 str: gӚ_`
}

무제한의 수명을 피할 수 있는 가장 쉬운 방법은 함수 경계에서 수명을 생략하는 것입니다. 출력 수명이 생략되면 반드시 입력 수명에 제한되게 되니까요. 당연히 잘못된 수명에 제한될 수도 있겠지만, 이런 것들은 보통 메모리 안전이 흔하게 침범당하게 두기보다는, 컴파일 오류를 야기할 뿐입니다.

함수 안에서 수명을 제한하는 것은 더 오류가 일어나기 쉽습니다. 수명을 제한하는 가장 안전하고 가장 쉬운 방법은 제한된 수명이 있는 함수에서 반환하는 것입니다. 그러나 이것을 받아들일 수 없다면, 레퍼런스를 특정한 수명이 있는 위치에 놓을 수 있습니다. 불행히도 함수 안에서 연관된 모든 수명들을 다 나열할 수는 없습니다.