lifetime
이 이렇게도 쓰이는지 알게되어 작성해본다.
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
Builder::new().spawn(f).expect("failed to spawn thread")
}
위 코드는 std::thread::spawn
함수의 정의 부분이다.
자세히 보면 타입을 정의하는 곳에 'static
이 붙은 것을 볼 수 있다. 이것은 라이프타임
의 문법으로 보통 &'static str
이런 식으로 사용된다. 그렇다면 여기서 이것이 쓰이는 진짜 의미가 뭔지 알아보겠다.
F: Send + 'static
여기서 'static
은 타입 F
가 어떤 참조도 포함하고 있지 않거나, 만약 포함하고 있다면 그 모든 참조들은 적어도 'static
라이프타임을 가져야 한다는 의미이다.
스레드의 경우 실행 순서가 보장되지 않고, 언제 시작해서 언제 끝날지 예측이 어렵다. 클로저가 특정 변수를 캡처하였는데 이후 해당 스레드가 호출이 되면서 클로저가 실행될 때 캡처한 변수가 가르키는 값이 이미 사라져있을 수 있다. 따라서 이런 상황을 방지하기 위해서 'static
라는 제약을 걸어주는 것이다.
fn test_func<T>(x: T)
where
T: std::fmt::Display + 'static
{
println!("{}", x);
}
fn main() {
let winter = "winter";
test_func(winter);
let name = "카리나".to_string();
let ref_name = name.as_str();
test_func(ref_name);
}
위 예제의 경우 test_func
함수가 제네릭 타입을 매개변수로 받고 트레이트 바운드가 std::fmt::Display
를 구현하여 출력을 할 수 있도록 하였고, 'static
을 추가해줘서 타입 T
가 참조 값을 가지고 있지 않거나, 가지고 있더라도 'static
참조를 가지고 있어야 한다는 제약을 걸었다.
main
함수에서는 winter
라는 변수를 만들어서 'static str
타입으로 만들어주었고 test_func
의 매개변수로 넘겨 주었다. 이상이 없었다. 그러나 ref_name
의 경우에 name
을 참조하고 있는 참조 변수이고 test_func
의 매개변수로 넘겨주었을 때 라이프타임이 'static
이 아니기 때문에 에러가 발생했다.
타입을 정의할 때 라이프 타임이 사용될 수 있는 것을 알았다. 라이브러리들을 보면 트레이트 바운드가 복잡하게 설정된 경우가 있었는데 이전보다는 더 쉽게 볼 수 있을 것 같다.