Day 5:生命週期註標

學習目標

  • 理解為何需要生命週期(lifetime)
  • 學會寫生命周期註標 'a
  • 讓借用安全地被編譯器驗證

今日重點

問題:回傳哪個借用?

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() { x } else { y }
}

編譯器不知道回傳的引用該跟 x 還是 y 綁在一起。需要註標告訴它。

生命週期註標 'a

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

「x、y、回傳值的生命週期都必須至少跟 'a 一樣長」— 讓編譯器檢查借用不會懸垂。

結構體中的生命週期

struct ImportantExcerpt<'a> {
    part: &'a str,   // 這個借用必須存活跟結構體一起
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 { 3 }
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().unwrap();
    let excerpt = ImportantExcerpt { part: first_sentence };
    println!("{}", excerpt.part);
}

練習

// 1. 為何下面會出錯?試著加上生命週期註標修好:
// fn first_word(s: &str) -> &str { ... }

// 2. 兩個引用有不同生命週期:
fn take_longer<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { x }

自我檢查

  • 能解釋生命週期解決的問題(懸垂引用)
  • 會寫函式生命週期註標 <'a>
  • 知道結構體持有引用時也要生命週期參數
  • 知道多半情況靠「生命週期省略規則」不需寫

深入連結

  • The Book 第 10 章「Lifetimes」