2012:rustpkg 與自舉之路——套件管理的實驗#
事件#
2012 年,Rust 0.4 發佈,編譯器 rustc 完全自舉(用 Rust 寫成)。同年推出實驗性套件管理工具 rustpkg,嘗試自動從版本控制系統抓取依賴並建置。
為何重要#
- rustpkg 的教訓:它直接依賴 git URL 與目錄慣例,沒有集中登錄、沒有版本鎖定,重現建置(reproducible build)幾乎不可能。這個失敗直接催生了 2014 年的 Cargo 設計。
- 類別系統大瘦身:2012–2014 年間,Rust 刪除了大量早期過度設計的特性——GC 指標
@與~的雙軌制、型別類(kind)系統、綠色執行緒(green threads)。 - 這段「刪除期」確立了 Rust 設計哲學:寧可延後 1.0,也要語言「少而精」。
理論與實用原因#
- 理論原因:早期
@T(GC 指標)與~T(唯一指標)並存,讓型別系統有兩套所有權規則;語言設計者體認到「唯一指標 + 借用」即可表達一切,GC 應交給函式庫而非語言核心。 - 實用原因:綠色執行緒(每個 task 有自己的 stack)與 Servo 需要的「與 C 程式碼、真實作業系統執行緒互通」相衝突;刪除綠色執行緒換來與 OS 執行緒完全對齊的 1:1 模型。
程式範例#
早期雙軌記憶體模型(2012 年前後,後來被刪除):
// 早期 Rust(已移除的語法)
let gc_box = @String::from("gc 管理"); // @:垃圾回收指標
let own_box = ~String::from("唯一所有"); // ~:唯一指標(後來成為 Box)
兩套規則並行讓型別系統與學習成本都翻倍,最終刪除 @、把 ~ 改名為 Box:
// 現代 Rust:GC 移出語言核心,交給函式庫型別
let shared = std::rc::Rc::new(String::from("引用計數,單執行緒"));
let thread_shared = std::sync::Arc::new(String::from("原子計數,可跨執行緒"));
let boxed = Box::new([0u8; 64]); // 唯一所有權,離開作用域即釋放
綠色執行緒被刪除,改為與 OS 執行緒 1:1 對齊:
use std::thread;
// 現代 Rust:thread::spawn 就是真實作業系統執行緒
let h = thread::spawn(|| println!("跑在真正的 OS thread 上"));
h.join().unwrap();
彌補了什麼缺陷#
彌補了 Rust 自己「早期過度設計、語法負擔重、兩套記憶體模型並行」的缺陷——透過刪除而非添加,語言核心縮小到足以長期維護的規模。