生命週期省略規則(lifetime elision)
如果每個碰到參考的函式都逼你親手寫出生命週期參數,Rust 程式碼會被 'a 和 'b 淹沒。實務上你幾乎從不寫它們。原因就是生命週期省略規則:一小組固定的模式,由編譯器套用來替你補上那些顯而易見的生命週期。它們不是猜測也不是魔法——它們是三條決定性的規則,只在答案毫無歧義時才成功;當它們無法決定時,編譯器就乾脆請你自己把生命週期寫出來。
規則正好有三條,依序套用到函式簽章上。規則一:每個沒寫生命週期的輸入參考,各自拿到一個全新、互異的生命週期參數(第一個 &T 輸入拿到 'a,第二個拿到 'b,依此類推)。規則二:若輸入生命週期恰好只有一個,這個生命週期就指派給所有輸出參考。所以 fn first(s: &str) -> &str 會被編譯器讀成 fn first<'a>(s: &'a str) -> &'a str,正是你的本意。規則三:若其中一個輸入是 &self 或 &mut self(也就是方法),self 的生命週期就指派給所有輸出參考——因為方法絕大多數回傳的是綁定到接收者的借用。若套完三條規則後仍有輸出參考沒有生命週期,省略就失敗,編譯器報錯,請你自己標註。這正是為什麼上一條的 longest 函式需要明寫 'a:它有兩個輸入參考,所以規則二不適用,又沒有 self,所以規則三也不適用。
為何重要:省略是可讀性上的便利,而非意義上的改變。標註版和省略版編譯出完全相同的約束;省略形式只是編譯器會展開的語法糖。常見誤解是以為省掉生命週期會讓借用檢查變得「比較鬆」或被略過——並不會。檢查器照樣一模一樣地跑;省略只決定標籤是你寫還是編譯器寫。當省略推出一個你不想要的關係時(罕見,但多輸入時可能發生),解法就是明寫生命週期,精確說出哪個輸出借自哪個輸入。
// 只有一個輸入參考 -> 規則二把輸出綁到它。不需要 'a。 fn first_word(s: &str) -> &str { s.split(' ').next().unwrap_or("") } // 編譯器讀成: // fn first_word<'a>(s: &'a str) -> &'a str // 兩個輸入參考且沒有 self -> 省略「失敗」,你必須標註。 // fn pick(a: &str, b: &str) -> &str { a } // 錯誤:缺少生命週期
省略是三條決定性的規則;當它們無法釘住每個輸出生命週期時,編譯器就請你自己來。
省略絕不放鬆借用檢查;它只決定標籤由誰來寫。若三條規則無法解出每個輸出生命週期,程式就無法編譯,直到你自己標註為止。