Rust

Rust 是由 Mozilla 主導開發的通用、編譯型程式語言。設計準則為 “安全、併發、實用”，支援函式式、並行式、過程式以及面向物件的程式設計風格。

Rust 語言原本是 Mozilla 員工 Graydon Hoare 的個人專案，而 Mozilla 於 2009 年開始贊助這個專案 ，並且在 2010 年首次公開。也在同一年，其編譯器原始碼開始由原本的 OCaml 語言轉移到用 Rust 語言，進行自我編譯工作，稱做「rustc」，並於 2011 年實際完成。這個可自我編譯的編譯器在架構上採用了 LLVM 做為它的後端。

第一個有版本號的 Rust 編譯器於 2012 年 1 月釋出。Rust 1.0 是第一個穩定版本，於 2015 年 5 月 15 日釋出。

Rust 在完全公開的情況下開發，並且相當歡迎社群的回饋。在 1.0 穩定版之前，語言設計也因為透過撰寫 Servo 網頁瀏覽器排版引擎和 rustc 編譯器本身，而有進一步的改善。它雖然由 Mozilla 資助，但其實是一個共有專案，有很大部分的程式碼是來自於社群的貢獻者。

設計

Rust 的設計目標之一，是要使設計大型的網際網路客戶端和伺服器的任務變得更容易。因此更加強調安全性、記憶體配置、以及並行處理等方面的特性。

1.1 效能

在效能上，具有額外安全保證的程式碼會比 C++ 慢一些，例如 Rust 對陣列進行操作時會進行邊界檢查（儘管可以透過一些方式繞過），而 C++ 則不會，但是如果等價的程式碼作手工檢查，則兩者效能上是相似的。

1.2 編譯報錯

比起 C/C++，Rust 編譯器的對於程式碼中錯誤的提示更清晰明瞭，開發者可根據提示輕鬆地修復程式碼中的錯誤。

1.3 編譯速度

由於其編譯器會做出額外的安全檢查，Rust 的編譯速度有時低於 C/C++。

1.4 語法

Rust 的語法設計，與 C 語言和 C++ 相當相似，區塊（block）使用大括號隔開，控制流程的關鍵字如 if、else、while 等等。在保持相似性的同時，Rust 也加進了新的關鍵字，如用於模式匹配的 match（與 switch 相似）則是使用 C/C++ 系統程式語言的人會相對陌生的概念。儘管在語法上相似，Rust 的語義（semantic）和 C/C++ 非常不同。

1.5 記憶體安全

為了提供記憶體安全，它的設計不允許空指標和懸空指標。指標只能透過固定的初始化形態來建構，而所有這些形態都要求它們的輸入已經分析過了。Rust 有一個檢查指標生命期間和指標凍結的系統，可以用來預防在 C++ 中許多的型別錯誤，甚至是用了智慧指標功能之後會發生的型別錯誤。

1.6 所有權

Rust 設計了一個所有權系統，其中所有值都有一個唯一的所有者，並且值的作用域與所有者的作用域相同。值可以透過不可變引用（&T）、可變引用（&mut T）或者透過值本身（T）傳遞。任何時候，一個變數都可以有多個不可變引用或一個可變引用，這實際上是一個顯式的讀寫鎖。Rust 編譯器在編譯時強制執行這些規則，並檢查所有引用是否有效。

1.7 記憶體管理

早期的 Rust 雖然有垃圾回收系統，但非如 Java 或.NET 平臺的全自動垃圾回收。Rust 1.0 已不再使用垃圾回收器，而是全面改用基於引用計數的智慧指標來管理記憶體。

1.8 型別與多型

它的型別系統直接地模仿了 Haskell 語言的型別類概念，並把它稱作「traits」，可以把它看成是一種特設多型。Rust 的作法是透過在宣告型別變數（type variable）的時候，在上面加上限制條件。至於 Haskell 的高階型別變數（Higher-kinded polymorphism）則還未支援。

型別推導也是 Rust 提供的特性之一，使用 let 語法宣告的變數可以不用宣告型別，亦不需要初始值來推斷型別。但如果在稍後的程式中從未指派任何值到該變數，編譯器會發出編譯時（compile time）錯誤。函式可以使用泛型化引數（generics），但是必須繫結 Trait。不能使用方法或運運算元而不宣告它們的型別，每一項都必確明確定義。

Rust 的物件系統是基於三樣東西之上的，即實作（implementation）、Trait 以及結構化資料（如 struct）。實作的角色類似提供 Class 關鍵字的程式語言所代表的意義，並使用 impl 關鍵字。繼承和多型則透過 Trait 實現，它們使得方法（method）可以在實作中被定義。結構化資料用來定義欄位。實作和（trait）都無法定義欄位，並且只有（trait）可以提供繼承，藉以躲避 C++ 的「鑽石繼承問題」（菱型缺陷）。

歷史

2006 年，Rust 作為 Graydon Hoare 的個人專案首次出現。

2009 年，Graydon Hoare 成為 Mozilla 僱員。

2010 年，Rust 首次作為 Mozilla 官方專案出現。同年，Rust 開始從初始編譯（由 OCaml 寫成）轉變為自編譯。

2011 年，Rust 成功的完成了移植。Rust 的自編譯器採用 LLVM 作為其編譯後端。

2012 年 1 月 20 日，第一個有版本號的預覽版 Rust 編譯器釋出。

2013 年 4 月 4 日，Mozilla 基金會宣佈將與三星集團合作開發瀏覽器排版引擎 Servo，此引擎將由 Rust 來實作。

2015 年 5 月 16 日，Rust 1.0.0 釋出。

2020 年 3 月 27 日，Rust 核心團隊成員 Steve Klabnik 在官方部落格發表了一篇名為《Goodbye, docs team》的文章，敘述了 Rust 文件的現狀。

2021 年 2 月 8 日，AWS、華為、Google、微軟以及 Mozilla 宣佈成立 Rust 基金會，並承諾在兩年時間裡每年投入不少於 100 萬美元的預算，以用於 Rust 專案的開發、維護和推廣。

2022 年 9 月 19 日，Linux 初始開發者 Linus Torvalds 表示在 Linux 核心 6.1 版中會有對 Rust 的初步支援。

2023 年 4 月 6 日，Rust 基金會發布了新商標政策草案，修訂了關於如何使用 Rust 標誌和名稱的規則，導致了 Rust 使用者社群的負面反應和抗議。

生態系統

除了編譯器和標準庫，Rust 生態系統還包括用於軟體開發的額外元件。官方推薦使用 Rustup，一個 Rust 工具鏈安裝程式來管理這些元件。

3.1 Cargo

Cargo 是 Rust 的軟體包管理器，用來下載和構建依賴關係。Cargo 還充當了 Clippy 和其他 Rust 元件的封裝器。它要求專案遵循一定的目錄結構。

Cargo.toml 檔案指定了專案所需的依賴和版本要求，告訴 Cargo 哪些版本的依賴關係與該包相容。Cargo 預設從 crates.io 中獲取依賴，但 Git 倉庫和本地檔案系統中的包也可以作為依賴。

3.2 整合開發環境支援

rust-analyzer 是一系列工具，可以透過語言伺服器協議為整合開發環境（IDE）和文字編輯器提供有關某一 Rust 專案的資訊。利用它，開發者可以在編輯 Rust 程式碼時使用自動完成和編譯錯誤顯示等功能。

程式碼示例

下面的程式碼在 Rust 1.3 中測試透過。

4.1 Hello World

fn main {println!("Hello, World!");

}

如果不想使輸出包含換行符 (\n)，可以使用 print! 巨集代替 println! 巨集。

4.2 階乘

下面是三個不同版本的階乘函式，分別以遞迴、迴圈和迭代器的方法寫成：

// 這個函式的 if-else 語句中展示了 Rust 中可選的隱式返回值，可用於寫出更像函式式程式設計風格的程式碼

// 與 C++ 和其他類似的語言不同，Rust 中的 if-else 結構不是語句而是運算式，有返回值

fn recursive_factorial (n: u32) -> u32 {

if n u32 {

// 變數用 `let` 定義，`mut` 關鍵字使得變數可以變化

let mut i = 1u32;

let mut result = 1u32;

while i u32 {

// 迭代器有多種用於變換的函式

// |accum, x| 定義了一個匿名函式

// 內聯展開等最佳化方法會消去區間和 fold，使本函式的執行效率和上一個函式相近

(1..n + 1).fold (1, |accum, x| accum * x)

}

fn main {println!("Recursive result: ", recursive_factorial (10));

println!("Iterative result: ", iterative_factorial (10));

println!("Iterator result: ", iterator_factorial (10));

}

4.3 平行計算

一個簡單的 Rust 平行計算例子：

use std::thread;

// 這個函式將建立十個同時並行的執行緒

// 若要驗證這一點，可多次執行這個程式，觀察各執行緒輸出順序的隨機性

fn main {

// 這個字串是不可變的，因此可以安全地同時被多個執行緒訪問

let greeting = "Hello";

let mut threads = Vec::new ;

// `for` 迴圈可用於任何實現了 `iterator` 特性的型別

for num in 0..10 {

threads.push (thread::spawn (move

{

// `println!` 是一個可以靜態檢查格式字串型別的巨集

// Rust 的巨集是基於結構的（如同 Scheme）而不是基於文字的（如同 C）

println!(" from thread number ", greeting, num);

}));

}

// 收集所有執行緒，保證它們在程式退出前全部結束

for thread in threads {thread.join .unwrap ;}

}

參閱

Servo