Rust是由Mozilla[11]主導開發的通用、編譯型編程語言。設計準則為「安全、並發、實用」[12][13],支持函數式、並行式、過程式以及面向對象的程式設計風格。
編程範型 | 編譯語言、並行計算、 函數式、指令式、 物件導向、結構化 |
---|---|
設計者 | Graydon Hoare |
實作者 | Mozilla |
面市時間 | 2010年 |
當前版本 |
|
型態系統 | 靜態類型、強型別、 類型推論、結構類型 |
操作系統 | Linux、macOS、Windows FreeBSD、Android、iOS等[2] |
許可證 | Apache許可證2.0及MIT許可證[3] |
文件擴展名 | .rs、.rlib |
網站 | rust-lang.org |
啟發語言 | |
Alef[4]、C#[4]、C++[4]、Cyclone[4][5] Erlang[4]、Haskell[4]、Hermes[4]、Limbo[4] Newsqueak[4]、NIL[4]、OCaml[4]、Ruby[4] Scheme[4]、Standard ML[4]、Swift[4][6] | |
影響語言 | |
C# 7[7]、Elm[8]、Idris[9]、Swift[10]、Carbon |
Rust語言原本是Mozilla員工Graydon Hoare的個人專案,而Mozilla於2009年開始贊助這個專案 [14],並且在2010年首次公開[15]。也在同一年,其編譯器原始碼開始由原本的OCaml語言轉移到用Rust語言,進行自我編譯工作,稱做「rustc」[16],並於2011年實際完成[17]。這個可自我編譯的編譯器在架構上採用了LLVM做為它的後端。
第一個有版本號的Rust編譯器於2012年1月釋出[18]。Rust 1.0是第一個穩定版本,於2015年5月15日釋出[19]。
Rust在完全公開的情況下開發,並且相當歡迎社群的回饋。在1.0穩定版之前,語言設計也因為透過撰寫Servo網頁瀏覽器排版引擎和rustc編譯器本身,而有進一步的改善。它雖然由Mozilla資助,但其實是一個共有專案,有很大部分的程式碼是來自於社群的貢獻者[20]。
設計
Rust的設計目標之一,是要使設計大型的網際網路客戶端和伺服器的任務變得更容易[21]。因此更加強調安全性、記憶體配置、以及並行處理等方面的特性。
在效能上,具有額外安全保證的代碼會比C++慢一些,例如Rust對數組進行操作時會進行邊界檢查(儘管可以通過一些方式[22]繞過[23]),而C++則不會,但是如果等價的C++代碼作手工檢查,則兩者效能上是相似的[24]。
比起C/C++,Rust編譯器的對於代碼中錯誤的提示更清晰明瞭,開發者可根據提示輕鬆地修復代碼中的錯誤。
由於其編譯器會做出額外的安全檢查,Rust的編譯速度有時低於C/C++。
Rust的語法設計,與C語言和C++相當相似,區塊(block)使用大括號隔開,控制流程的關鍵字如if
、else
、while
等等。在保持相似性的同時,Rust也加進了新的關鍵字,如用於模式匹配的match
(與switch
相似)則是使用C/C++系統程式語言的人會相對陌生的概念。儘管在語法上相似,Rust的語義(semantic)和C/C++非常不同。
為了提供內存安全,它的設計不允許空指標和懸空指標[25][26]。指針只能透過固定的初始化形態來建構,而所有這些形態都要求它們的輸入已經分析過了[27]。Rust有一個檢查指標生命期間和指標凍結的系統,可以用來預防在C++中許多的型別錯誤,甚至是用了智能指針功能之後會發生的型別錯誤。
Rust設計了一個所有權系統,其中所有值都有一個唯一的所有者,並且值的作用域與所有者的作用域相同。值可以通過不可變引用(&T
)、可變引用(&mut T
)或者通過值本身(T
)傳遞。任何時候,一個變量都可以有多個不可變引用或一個可變引用,這實際上是一個顯式的讀寫鎖。Rust編譯器在編譯時強制執行這些規則,並檢查所有引用是否有效。[28][29]
早期的Rust雖然有垃圾回收系統,但非如Java或.NET平台的全自動垃圾回收。Rust 1.0已不再使用垃圾回收器,而是全面改用基於引用計數的智能指針來管理內存。
它的型別系統直接地模仿了Haskell語言的類型類概念,並把它稱作「traits」,可以把它看成是一種特設多態。Rust的作法是透過在宣告型別變數(type variable)的時候,在上面加上限制條件。至於Haskell的高階型別變數(Higher-kinded polymorphism)則還未支援。
型別推導也是Rust提供的特性之一,使用let
語法宣告的變數可以不用宣告型別,亦不需要初始值來推斷型別。但如果在稍後的程式中從未指派任何值到該變數,編譯器會發出編譯時(compile time)錯誤[30]。函數可以使用泛型化參數(generics),但是必須綁定Trait。不能使用方法或運算子而不宣告它們的型別,每一項都必確明確定義。
Rust的物件系統是基於三樣東西之上的,即實作(implementation)、Trait以及結構化資料(如struct)。實作的角色類似提供Class關鍵字的程式語言所代表的意義,並使用impl
關鍵字。繼承和多型則透過Trait實現,它們使得方法(method)可以在實作中被定義。結構化資料用來定義欄位。實作和(trait)都無法定義欄位,並且只有(trait)可以提供繼承,藉以躲避C++的「鑽石繼承問題」(菱型缺陷)。
歷史
2006年,Rust作為Graydon Hoare的個人項目首次出現。
2009年,Graydon Hoare成為Mozilla雇員[14]。
2010年,Rust首次作為Mozilla官方項目出現[15]。同年,Rust開始從初始編譯(由OCaml寫成)轉變為自編譯[16]。
2011年,Rust成功的完成了移植[17]。Rust的自編譯器採用LLVM作為其編譯後端。
2012年1月20日,第一個有版本號的預覽版Rust編譯器發布[18]。
2013年4月4日,Mozilla基金會宣布將與三星集團合作開發瀏覽器排版引擎Servo,此引擎將由Rust來實作[31]。
2015年5月16日,Rust 1.0.0發布[32]。
2020年3月27日,Rust核心團隊成員Steve Klabnik在官方博客發表了一篇名為《Goodbye, docs team 》的文章,敘述了Rust文檔的現狀[33]。
2021年2月8日,AWS、華為、Google、微軟以及Mozilla宣布成立Rust基金會[34][35],並承諾在兩年時間裡每年投入不少於 100 萬美元的預算,以用於 Rust 項目的開發、維護和推廣[36]。
2022年9月19日,Linux初始開發者林納斯·托瓦茲表示在Linux核心6.1版中會有對Rust的初步支援[37]。
2023年4月6日,Rust基金會發布了新商標政策草案,修訂了關於如何使用Rust標誌和名稱的規則,導致了Rust用戶社區的負面反應和抗議。[38]
生態系統
除了編譯器和標準庫,Rust生態系統還包括用於軟件開發的額外組件。官方推薦使用Rustup,一個Rust工具鏈安裝程序來管理這些組件。
Cargo是Rust的軟件包管理器,用來下載和構建依賴關係。Cargo還充當了Clippy和其他Rust組件的封裝器。它要求項目遵循一定的目錄結構。[39]
Cargo.toml文件指定了項目所需的依賴和版本要求,告訴Cargo哪些版本的依賴關係與該包兼容。Cargo默認從crates.io中獲取依賴,但Git倉庫和本地文件系統中的包也可以作為依賴。[40]
rust-analyzer 是一系列工具,可以通過語言服務器協議為集成開發環境(IDE)和文本編輯器提供有關某一Rust項目的信息。利用它,開發者可以在編輯Rust代碼時使用自動完成和編譯錯誤顯示等功能。[41]
代碼示例
下面的代碼在Rust 1.3中測試通過。
fn main() {
println!("Hello, World!");
}
如果不想使輸出包含換行符(\n),可以使用print!
巨集代替println!
巨集。
下面是三個不同版本的階乘函數,分別以遞迴、迴圈和迭代器的方法寫成:
// 這個函數的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並行計算例子:
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();
}
}
參考資料
參閱
外部連結
Wikiwand in your browser!
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.