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

### 性能

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

### 編譯報錯

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

### 編譯速度

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

### 語法

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

### 記憶體安全

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

### 所有權

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

### 記憶體管理

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

### 類型與多態

它的型別系統直接地模仿了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工具鏈安裝程序來管理這些組件。

### Cargo

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

Cargo.toml文件指定了項目所需的依賴和版本要求，告訴Cargo哪些版本的依賴關係與該包兼容。Cargo默認從crates.io中獲取依賴，但Git倉庫和本地文件系統中的包也可以作為依賴。

### 集成開發環境支持

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

## 代碼示例

下面的代碼在Rust 1.95中測試通過。

### Hello World

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

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

### 階乘

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

```rust
// 這個函數的if-else語句中展示了Rust中可選的隱式返回值，可用於寫出更像函數式程式設計風格的代碼
// 與C++和其他類似的語言不同，Rust中的if-else結構不是語句而是運算式，有返回值
fn recursive_factorial(n: u32) -> u32 {
    if n <= 1 {
        1
    } else {
        n * recursive_factorial(n - 1)
    }
}

fn iterative_factorial(n: u32) -> u32 {
    // 變數用`let`定義，`mut`關鍵字使得變數可以變化
    let mut i = 1u32;
    let mut result = 1u32;
    while i <= n {
        result *= i;
        i += 1;
    }
    result // 顯式返回值，與上一個函數不同
}

fn iterator_factorial(n: u32) -> 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));
}
```

### 並行計算

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

```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

## 外部連結

- 官方網站（簡體中文、正體中文）
- The Rust-dev Archives（郵件列表）
- Rust主原始碼庫及缺陷跟蹤系統於Github
- Rust語言Wiki於Github
- Rust教學

## 基本資料

- 日語原文：Rust
- 編程范型：編譯語言、並行計算、函數式、指令式、物件導向、結構化
- 發行時間：2010年
- 設計者：Graydon Hoare
- 開發者：Mozilla
- 類型系統：靜態類型、強型別、類型推論、結構類型
- 受影響於：Alef (程式語言)、C#、C++、Cyclone (程式語言)、Erlang、Haskell、Hermes (程式語言)、Limbo、Newsqueak、NIL (程式語言)、OCaml、Ruby、Scheme、Standard ML、Swift
- 施影響於：C# 7、Elm、Idris、Swift、Carbon
- 作業系統：Linux、macOS、Windows、FreeBSD、Android、iOS等
- 許可證：Apache許可證2.0及MIT許可證
- 文件擴展名：.rs、.rlib