09. 라이프타임 입문 ('a 명시·생략 규칙)
라이프타임은 참조가 유효한 기간을 표현하는 컴파일 타임 마커입니다. 'a 같은 표기로 명시하지만, 대부분의 경우 컴파일러가 라이프타임 생략(elision) 규칙으로 자동 추론해 줍니다. 이 강의에서 라이프타임이 왜 필요한지, 언제 명시해야 하는지, 그리고 'static 의 의미까지 정리합니다.
이 강의에서 배우는 것
- 1왜 라이프타임이 필요한지 dangling reference 예시로 안다
- 2'a 표기를 함수 시그니처와 struct 에 붙인다
- 3라이프타임 생략 3규칙을 안다
- 4'static 의 의미를 구분한다
- 5라이프타임 에러 메시지를 읽고 해결한다
소개
참조가 가리키는 데이터가 사라지면 참조는 더 이상 유효하지 않습니다 — dangling reference. Rust 는 이걸 컴파일 타임에 막기 위해 모든 참조에 라이프타임을 추적합니다. 대부분 자동이라 평소엔 의식할 일이 없지만, 함수가 참조를 인자로 받아 참조를 반환할 때 등에서 명시가 필요해집니다.
핵심 개념
1) 라이프타임이 푸는 문제
fn main() {
let r;
{
let x = 5;
r = &x; // x 가 곧 사라질 텐데?
} // x drop
println!("{}", r); // error: `x` does not live long enough
}2) 라이프타임 명시 'a
함수가 참조를 받아 참조를 반환할 때 컴파일러가 둘의 관계를 알아야 합니다. `'a` 는 임의의 이름(보통 a, b, c)으로 같은 라이프타임을 가짐을 의미.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}3) 라이프타임 생략 3규칙
- 각 참조 인자는 자기만의 라이프타임을 부여받음
- 인자가 하나뿐이면 그 라이프타임이 반환값에도 부여됨
- 메서드에서 첫 인자가 `&self` 또는 `&mut self` 면 self 의 라이프타임이 반환값에 부여됨
이 세 규칙으로 추론이 끝나면 명시 생략 가능 — 그래서 평소 코드에서 'a 가 거의 안 보입니다.
4) 'static — 프로그램 전체 수명
`&'static str` 은 프로그램이 살아있는 동안 유효한 참조. 문자열 리터럴이 그 예.
핵심 예제
라이프타임 명시가 필요한 경우 — 두 참조 중 하나를 반환:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
fn main() {
let s1 = String::from("long string");
let result;
{
let s2 = String::from("short");
result = longest(s1.as_str(), s2.as_str());
println!("longest = {}", result);
} // s2 drop — result 는 여기서만 유효
}struct 가 참조 필드를 가지면 라이프타임 필수:
struct Excerpt<'a> {
part: &'a str,
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().unwrap();
let e = Excerpt { part: first_sentence };
println!("{}", e.part);
}라이프타임 생략 — 컴파일러가 자동으로 채워주는 경우:
// 생략 가능 — 인자 하나, 규칙 2 적용
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &b) in bytes.iter().enumerate() {
if b == b' ' { return &s[0..i]; }
}
s
}
// 풀어쓰면: fn first_word<'a>(s: &'a str) -> &'a str { ... }자주 하는 실수
Q. 라이프타임을 어디까지 명시해야 하나요?
A. 컴파일러가 시킬 때만요. 생략 규칙으로 추론 안 되는 경우에만 에러가 나고, 그때 명시하면 됩니다. 처음부터 'a 를 남발할 필요 없습니다.
Q. 'static 을 붙이면 만능 아닌가요?
A. 아닙니다. 'static 은 "프로그램 전체 수명" 이라는 강한 제약이라 짧은 수명의 참조는 통과 못 합니다. 일반 함수 시그니처에 'static 을 강제하면 호출자 자유가 크게 줄어듭니다.
Q. 라이프타임이 다른 두 참조를 어떻게 반환하나요?
A. `<'a, 'b>` 로 둘 다 적고 `'b: 'a` 같은 outlives 제약을 걸거나, 보통은 둘 중 짧은 쪽으로 통일합니다. 라이프타임 산수가 복잡해지면 대개 설계가 잘못된 신호.
정리
- 라이프타임은 참조의 유효 기간을 컴파일러에 알려주는 마커
- 대부분 생략 3규칙으로 자동 추론됨
- 함수가 참조 ↔ 참조를 매핑할 때 명시 필요
- 'static 은 프로그램 전체 수명 — 만능 카드 아님
과제
- longest 함수를 두 개의 다른 라이프타임 'a, 'b 로 시도해보고 어떤 에러가 나는지 확인
- struct Book<'a> { title: &'a str, author: &'a str } 를 만들어 사용
- dangling reference 가 발생할 코드를 일부러 작성하고 컴파일러 메시지를 옮겨 적기