1. 為什麼需要生命週期(Lifetime)
在 Rust 中,所有的引用(reference)都有明確的存活範圍,編譯器必須確保引用的值在使用期間不會被釋放。
生命週期(Lifetime)就是 Rust 用來追蹤引用有效時間的一套標記系統,這能防止懸垂指標(dangling reference)等記憶體錯誤。
2. 基本例子:懸垂參考錯誤
fn main() {
let r;
{
let x = 5;
r = &x; // x 在這裡離開作用域
}
println!("{}", r); // 編譯錯誤:r 指向已被釋放的值
}
輸出(編譯錯誤):
error[E0597]: `x` does not live long enough
Rust 編譯器會主動拒絕這種可能導致無效引用的程式。
3. 函數中的生命週期註記
如果一個函數回傳引用,Rust 需要知道輸入與輸出的生命週期之間的關係。
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if s1.len() > s2.len() {
s1
} else {
s2
}
}
fn main() {
let s1 = String::from("rust");
let s2 = String::from("programming");
let result = longest(&s1, &s2);
println!("Longest: {}", result);
}
輸出:
Longest: programming
'a 是生命週期參數,用來告訴編譯器:回傳值的生命週期與參數中的最短者相同。
4. 結構體中的生命週期
若結構體中有引用欄位,也必須註明生命週期:
struct Book<'a> {
title: &'a str,
}
fn main() {
let name = String::from("Rust Book");
let b = Book { title: &name };
println!("Book title: {}", b.title);
}
輸出:
Book title: Rust Book
5. 靜態生命週期 'static
'static 代表資料在整個程式生命週期中都有效(例如字面字串常量)。
fn main() {
let s: &'static str = "Hello, Rust!";
println!("{}", s);
}
這是最長的生命週期,一般只在全域資料或常量中使用。
6. 學習心得與補充
今天學的生命週期讓我更理解為什麼 Rust 能在沒有垃圾回收的情況下仍保持記憶體安全。以前在 C++中,我常會不小心把指標指到已釋放的記憶體區塊,而 Rust 直接在編譯階段就阻止這種情況發生。雖然一開始看到 'a、'static 這些標註會有點抽象,但當我理解它其實只是保證引用活得夠久的規則時,一切就變得合理了。我覺得這個系統的設計很聰明,既能靜態檢查,又不影響執行效率。透過這次練習,我開始明白 Rust 的所有權、借用與生命週期三者是密不可分的核心。雖然這個主題需要時間消化,但也讓我看到 Rust 安全機制的底層邏輯。