跳轉到

2022:GAT、let-else 與 Linux 核心合併——主流化的元年#

事件#

2022 年的三件大事:GAT(1.65,11 月)、let-else(1.65)、以及 Linux 6.1 正式合併 Rust 支援(12 月)——Rust 成為第一個(C 之外)進入 Linux 核心的語言。

為何重要#

  • GAT(Generic Associated Types):trait 的關聯型別終於可以自帶泛型參數——
    trait LendingIterator {
        type Item<'a> where Self: 'a;
        fn next(&mut self) -> Option<Self::Item<'_>>;
    }
    
  • 彌補的缺陷:1.0 的關聯型別無法表達「借用自 &mut self 的項目」,導致迭代器借用自身資料的抽象(如資料庫驅動、串流處理)寫不出來,只能靠 unsafe 或 HRTB 變通。
  • 理論原因:GAT 讓 trait 更接近高階型別構造子(higher-kinded types)的表達力,是 Rust 型別系統對 ML 型別類理論的再次追趕。
  • let-else:let Some(x) = opt else { return; };——把「不符則提前離開」的模式比對壓縮成一行,補齊 ? 之後的人體工學缺口。
  • Linux 核心合併:Linus Torvalds 親自合併。意義:記憶體安全從應用層進入世界上最受審計的核心;CISA/NSA 同年發佈記憶體安全指引,Rust 成為官方建議。

理論與實用原因#

  • 理論原因:let-else 是「early return」模式的顯式化(與 ? 同一家族);GAT 則是型別系統理論(關聯型別的參數化)在工程上的落地。
  • 實用原因:核心與驅動程式是記憶體漏洞重災區;Google 統計顯示 Android 約七成安全漏洞源於記憶體錯誤,Rust 導入後 Rust 相關元件漏洞比例趨近於零。

程式範例#

GAT 之前——借用式迭代抽象寫不出來:

// 想要:迭代器借用自身資料,每次 next 回傳借用項
// 1.0 的關聯型別無法表達「Item 的壽命綁定 &mut self」:
trait LendingIterator {
    type Item;                    // 無法寫成 type Item<'a>
    fn next(&mut self) -> Option<&Self::Item>;   // 壽命關係表達不了
}
// 只能靠 unsafe 或終身 HRTB 變通,或者 Box 裝箱犧牲效能

GAT 之後(1.65)——關聯型別自帶泛型參數:

trait LendingIterator {
    type Item<'a> where Self: 'a;               // Item 有自己的壽命參數
    fn next(&mut self) -> Option<Self::Item<'_>>;
}

struct Counter { data: Vec<u32>, pos: usize }

impl LendingIterator for Counter {
    type Item<'a> = &'a u32 where Self: 'a;
    fn next(&mut self) -> Option<&u32> {
        let item = self.data.get(self.pos)?;
        self.pos += 1;
        Some(item)
    }
}

let-else(1.65)——前置條件檢查一行搞定:

fn parse(config: &str) -> u16 {
    // 之前:
    // let port = match config.parse::<u16>() {
    //     Ok(p) => p,
    //     Err(_) => return 8080,
    // };

    // let-else:不符則提前離開
    let Ok(port) = config.parse::<u16>() else { return 8080; };
    let Some(timeout) = std::env::var("TIMEOUT").ok() else { return port; };
    port + timeout.parse().unwrap_or(0)
}

Linux 核心:Rust 驅動的安全寫法:

// Linux 6.1 起:Rust 核心模組(如 Rust for Linux 的字元裝置範例)
use kernel::prelude::*;

module! {
    type: RustChrdev,
    name: "rust_chrdev",
    license: "GPL",
}
// 核心內的緩衝區、指標操作由型別系統檢查——C 驅動的
// 緩衝區溢位類漏洞在這裡編譯不過

彌補了什麼缺陷#

彌補了 Rust「無法表達借用式迭代抽象(GAT)」與「前置條件檢查樣板過多(let-else)」的缺陷;Linux 合併則彌補了「作業系統核心只有 C 一種選擇、記憶體漏洞無法根除」的歷史缺陷。

相關條目#