本文爲InfoQ中文站特供稿件。首發地址爲: http://www.infoq.com/cn/articles/rust-core-components 。如需轉載。請與InfoQ中文站聯繫。html
原文發表於2015年12月22日,現依據以前約定將其全文轉發到我(Liigo)我的博客裏。git
Rust是一門強調安全、併發、高效的系統編程語言。無GC實現內存安全機制、無數據競爭的併發機制、無執行時開銷的抽象機制。是Rust獨特的優越特性。它聲稱攻克了傳統C語言和C++語言幾十年來飽受責難的內存安全問題,同一時候還保持了很是高的執行效率、很是深的底層控制、很是廣的應用範圍,在系統編程領域具備強勁的競爭力和廣闊的應用前景。github
從狹義的角度說。Rust編程語言。就是其語言自己,一份以人類語言描寫敘述的計算機編程語言的規範文檔。編程
然而單單語言自己,僅具備理論價值;要發揮其有用價值,每每還要有編譯器、標準庫、執行環境等一系列配套設施。共同組成一套完整的生態體系。後端
從廣義的角度說,Rust編程語言包括了:語言規範(reference)、編譯器(rustc)、執行時(runtime)、標準庫(std)、核心庫(core)、庫(crates)、包管理器(cargo)、社區(communities)等等。安全
本文將比較具體的介紹廣義上的Rust編程語言各個組成部分。markdown
Rust語言規範規定了Rust編程語言的語法和語義。跟其它語言規範同樣。充滿枯燥的文字。真正願意通讀下來的人很是少。大多數人經過0基礎教程學習語言的基本的語法和語義。僅在必要時翻閱或查閱語言規範的局部內容。(嚴格來講。Rust眼下提供的這份文檔並不算是語言規範文檔(specification),而僅僅僅僅是參考文檔。)網絡
官方的rustc是眼下惟一的Rust編譯器(以前的rustboot編譯器早就被廢棄了)。它負責把Rust源碼編譯爲可執行文件、Rust庫(crates)或其它庫文件(.a/.lib/.so/.dll)。多線程
rustc是跨平臺的應用程序,其可執行文件名稱是 rustc (for Unix/Linux/…) 或 rustc.exe (for Windows),最基本的命令行調用方法是 rustc hello.rs
。併發
rustc具備交叉編譯功能,可以在當前平臺下編譯出可執行於其它平臺的應用程序和庫(但需要事先編譯或安裝目標平臺的工具鏈)。
rustc採用LLVM做爲編譯器後端,具備很是好的代碼生成和優化技術。支持不少目標平臺。
rustc眼下使用gcc做爲連接器(同一時候也執行時依賴glibc執行庫,從此可換用MUSL靜態庫,相關開發工做在進行中);從此在Windows平臺將支持使用MSVC做爲連接器(相關開發工做在進行中)。
rustc編譯出來的程序,支持用GDB和LLDB調試執行。用戶不需要更換本身已經熟悉的調試工具,Rust沒有也不需要本身專屬的調試器。
rustc是用Rust語言開發的,而且是開源的,最新源碼在這裏:https://github.com/rust-lang/rust/tree/master/src/librustc
在沒有明白上下文的狀況下,執行時(runtime)一般可被理解爲「執行時庫(runtime library)」或「執行時損耗(runtime overhead)」。
如下就這兩種狀況分別闡述。最後得出的結論是:Rust可以沒有執行時庫,且僅有很是小的執行時損耗。
編程語言的執行時庫,一般理解爲。其編譯出的可執行程序在執行時必須依賴的非操做系統自己的動態庫。好比C程序必須依賴msvcrt或glibc,Java程序必須依賴JRE。VB程序必須依賴msvbvm,易語言程序必須依賴krnln.fne/fnr,等等。因爲C執行時庫每每跟操做系統緊密集成(尤爲是類Unix系統),可以以爲C執行時庫是操做系統的一部分。進而以爲C沒有執行時庫(固然這裏見仁見智)。
假設認同這一點。那麼。通過靜態編譯生成的Rust程序。執行時僅依賴C執行時庫。也就可以以爲沒有執行時庫了。
即便不認同這一點。等之後Rust支持了靜態連接MUSL庫(同一時候拋棄掉glibc)。依舊可以作到沒有執行時庫。固然,動態編譯的Rust程序中執行時仍是必須依賴標準庫libstd-*.so等動態庫的,這是給予程序猿的額外可選項。
說Rust「可以」沒有執行時庫。就是說執行時庫不必的,程序猿擁有選擇權(而不是被迫必須接受執行時庫)。
那爲何說沒有執行時庫是一個優點呢?因爲執行時庫自己也有平臺依賴性和/或執行時依賴性,有執行時庫就意味着,你的程序僅僅能在執行時庫所支持的平臺下執行,也就是說它限制了程序的部署平臺。
而執行時庫支持哪些平臺並不是程序猿個體所能決定的。
就算執行時庫官方開發商決定向新的平臺移植。也每每受諸多因素干擾,好比十多年前試圖將JRE移植到手機平臺時就破費周折,甚至不得不大幅刪減功能、人爲製造了殘缺不全的手機版JRE。再試想,在一個沒有網絡系統、沒有文件系統,甚至沒有操做系統的嵌入式平臺上,你有可能在上面跑JRE環境嗎?作夢。
沒有了執行時庫。程序的所有代碼都是程序猿可控的(至於標準庫的影響,下文將會談到)。
(更寬泛地說,執行時庫居無定形。未必必定以獨立動態庫的形式存在,它也可能隱身於標準庫甚至是可執行文件內部。
僅僅要它給程序自己帶來了額外的且沒法消除的明顯的依賴和不可忽略的執行時損耗,咱們就統統以爲它是執行時(庫)。反過來講。假設執行時(庫)的執行時損耗小到必定程度,且沒有帶來額外的執行時依賴,咱們甚至可以以爲它不是執行時(庫)。此中斟酌。見仁見智。)
程序的執行時損耗。是指程序在執行過程當中所必須付出的額外的代價。好比Java的虛擬機、C#的垃圾回收器、腳本語言的解釋器等等。這些子系統自己在執行時都會消耗數量可觀的內存和CPU。影響程序和系統的執行性能。而Rust沒有虛擬機、垃圾回收器和解釋器。因此沒有這類執行時損耗。
此外,內存管理、棧管理、調用操做系統API和C庫等各類狀況下,都有可能產生額外的執行時損耗。
Rust執行時需要每一個函數執行morestack檢查棧溢出(morestack已被取消),爲了內存安全這是「必需的」檢查。而以C語言的思路去看可能就是「額外的」損耗。無論怎樣這項執行時損耗很是小。Unwinding僅發生在panic以後,不視爲執行時損耗。
Rust採用jemalloc管理內存(也可禁用)。不只沒有執行時損耗。反而帶來執行效率的明顯提高。
Rust的Rc類型以引用計數管理對象內存,Arc類型以Atomic引用計數管理對象內存,這是較小的執行時損耗。
但假設程序猿不主動使用Rc/Arc類型,則無需爲此付出額外的代價。
(Go語言的協程調度器。固然也有執行時損耗,但這在某種程度上是程序實現自身功能的必要,算不上「額外的」代價。假設不需要此功能則損耗很是小,故本文做者不視其爲執行時損耗。
而其經過channel共享內存、管理逐步連續增加的棧、調用C庫和系統API,則被視爲執行時損耗,因爲這些都是「非必要的」損耗,而且損耗還不小。)
(Java的JIT編譯器在執行時把字節碼編譯爲機器碼,算不算執行時損耗呢?損耗確定是有的,但僅在特定條件下觸發,且其帶來的收益可能遠大於損耗。是提高執行性能的必要步驟。故本文做者不以爲它引入了「額外的」代價,不視其爲執行時損耗。而Java的虛擬機和垃圾收集器,顯然是突出的執行時損耗。)
Rust的標準庫,爲絕大多數的、常規的Rust程序開發提供基礎支持、跨平臺支持。是應用範圍最廣、地位最重要的庫(沒有之中的一個)。其規模居中,既不像傳統C和C++標準庫那麼簡陋,也不像Java和.Net標準庫那樣一應俱全。
Rust標準庫的內容大體概括例如如下:
基礎的接口性數據類型
如 Copy, Send, Sized, Sync, Drop, Deref, Clone, Iterator, IntoIterator, Debug, Display, Option, Result, Error, Eq, Ord, Fn, Cell, Hash 等等。當中多數都被包括在 std::prelude 內。
這些簡明扼要的類型,構成了Rust生態系統的基石。假設標準庫不提供這些類型。讓第三方庫各行其是的話。整個生態系統將很是難造成協力。
基礎類型操做接口
如 bool, char, i8/u8, i16/u16, i32/u32, i64/u64, isize/usize, f32/f64, str/array/slice/tuple/pointer 等基礎類型數據的操做接口及事實上現。
常用的功能性數據類型
如 String, Vec, HashMap, Rc, Arc, Box, CString, OsString, SipHasher 等等。
知足常見的、常用的,或特定的功能需求。
常用的宏定義
如 println!, format!, assert!, try!, panic!, vec!, thread_local!, file!, line!, include! 等等。
基礎的或核心的宏。當中某些宏是藉助編譯器實現的。
跨平臺的I/O相關的系統功能
如 std::io, std::fs, std::path, std::env, std::process 等等。
跨平臺的網絡/多線程/同步相關係統功能
如 std::net, std::thread, std::sync 等等。
其它的不跨平臺的操做系統相關功能
如 std::os。爲各主流操做系統分別提供了專門的操做接口,便於實現系統特有的功能調用。
底層操做接口
如 std::mem, std::ptr, std::intrinsics 等。操做內存、指針、調用編譯器固有函數。
其它等等
Rust核心庫,可以理解爲是通過大幅精簡的標準庫。它被應用在標準庫不能覆蓋到的某些少數特定領域,如嵌入式開發。
前面提到過,標準庫應用範圍很是廣,爲絕大多數應用程序提供支持。但是在嵌入式開發、操做系統開發、裸金屬(bare metal)環境下,標準庫就無能爲力了。主要有如下兩個緣由致使標準庫的應用範圍受到必定的限制:
標準庫的「跨平臺」是指「跨主流操做系統平臺」,也就是跨 Windows、Unix/Linux、Mac/OSX 等少數幾個操做系統。
標準庫內有至關數量的API(如文件、網絡、多線程等)必須依賴操做系統提供的接口,到了非主流系統尤爲是嵌入式系統環境下,標準庫失去了底層系統的支撐根本就不可能工做。
標準庫內有至關數量的API(如String/Vec、Box、panic等)依賴內存申請和釋放功能,但是在操做系統開發、裸金屬(bare metal)環境下,要麼不存在這些功能。要麼需要本身開發。
這些限制對Rust標準庫來講事實上並不是問題。跟世界上大多數編程語言的標準庫同樣,爲主流系統的主流應用開發提供豐富的功能支持,纔是最重要的。
假設單純爲了提高應用範圍砍掉操做系統相關的功能,那標準庫也大概成了空殼子,功能性和有用性大打折扣,完全失去了標準庫的價值——誰能接受一個連文件、網絡、多線程功能都沒有的標準庫呢?
Rust的選擇是,在標準庫以外。再單獨提供一個核心庫,重點應對嵌入式應用開發。核心庫不依賴不論什麼操做系統,也不提供文件/網絡/多線程/內存申請釋放相關的不論什麼功能,於是可移植性更好、應用範圍更廣。當用Rust開發一個操做系統或硬件驅動或嵌入式應用時,你總不能期望去調用別的主流操做系統接口吧?那顯然是不切實際的。因此對核心庫來講。它缺乏的那些OS相關功能本來就是多餘的。
在代碼開頭寫上 #![no_std]
就表明放棄標準庫。而使用核心庫。核心庫裏面有:基礎的接口性數據類型(參見上文。下同)、基礎類型操做接口、常用的功能性數據類型、常用的宏定義、底層操做接口等,而且跟標準庫API差點兒是全然一致的;再配合alloc庫(或本身定製的alloc庫)又有了內存申請釋放功能;再加上collections庫。String/Vec/HashMap等也有了。
事實上從內部實現來講。標準庫裏的某些功能正是來源於核心庫(以及alloc/collections等)。
把多個Rust源碼文件(後綴名.rs)放一塊兒編譯出來,就獲得一個庫。庫一般以靜態庫.rlib或動態庫.so/.dll的形式存在。咱們稱Rust庫爲crate,就像別的語言把庫稱爲library或package差點兒相同一個意思。僅僅是習慣上的命名不一樣。
庫是Rust程序猿共享代碼和功能的基本單元。
編寫應用程序和軟件,無非就是綜合利用各類庫,官方的庫、本身的庫、第三方的庫,調用它們提供的接口(API)。再融合本身的業務邏輯。終於達成目的。
在已經編譯或安裝了某個庫xxx的前提下,要想調用這個庫。需首先在源碼首部增長這麼一行代碼:
extern crate xxx;
咱們不需要像Java操心CLASSPATH同樣操心Rust庫的載入路徑,因爲咱們有Cargo(如下會講到)。因爲咱們有靜態編譯。
眼下Rust已經有了大概3000多個公開的第三方庫,所有集中在 crates.io 站點上(如下也會講到)。這些庫絕大多數都是Github上面的開源項目。
我好像極少聽到有誰公佈二進制的庫(而不是公佈源碼)。
Cargo是Rust官方提供的包管理器(package manager),類似於Java界的Gradle。Cargo負責下載庫源碼,分析庫的依賴項,下載依賴項的源碼,再分析依賴項的依賴項,如此這般,終於把他們逐個編譯出來。一句話,就是處理下載(源碼)、依賴(第三方庫)、和編譯(生成庫或可執行文件)。
有了Cargo,無論多複雜的項目,無論有多複雜的依賴項,也僅僅需在項目根文件夾下執行這麼一條命令:
cargo build
Cargo包管理器跟crates.io站點造成了完整的生態系統。
crates.io就是一箇中心倉庫,全世界差點兒所有的Rust項目都被整合在此倉庫中。每一個項目都包括了一個Cargo.toml的配置文件,指定了自身的依賴項。
Cargo就是環繞Cargo.toml開展工做的。
在C和C++的世界裏。假設一個開源項目沒有不論什麼依賴,每每會被看成一項長處。因爲你們都知道。編譯帶有依賴項的源碼項目是很是麻煩的。尤爲是當依賴項又有依賴項的時候,尤爲是當依賴項的版本號號又不明白的時候。幾十年了,都沒出現一個被普遍接受的基於版本號的依賴管理和編譯工具,頗爲遺憾。
Rust不同,它一開始就有了Cargo。
Cargo是一個使人驕傲的優秀的工具。
它不只是一個工具。更是一個生態系統。
Rust有至關龐大的社區。僅參與開發Rust系統自己的開發人員就多達1300人,並持續增加。這類開發人員中,以Mozilla公司員工組成的約10人團隊爲核心,以來自世界各地的貢獻者爲輔助。
採用Rust開發應用的開發人員人數不少其它,但難以統計數量。固然,做爲新興語言,Rust社區規模相對Java、Python社區而言還稚嫩的很是,發展潛力無限。
Rust開發人員活動軌跡主要集中在Github站點、IRC在線聊天室、Reddit論壇和Rust官方論壇中。此外,環繞某些頗具雄心的項目還各自造成了獨立子社區。如Servo、Piston、MaidSafe、Redox等。
源碼倉庫、設計開發討論區:
- https://github.com/rust-lang/rust
- https://github.com/rust-lang/rfcs
- https://github.com/rust-lang/cargo
- https://internals.rust-lang.org
- https://client00.chat.mibbit.com/?server=irc.mozilla.org&channel=%23rustc
用戶應用討論提問區:
- https://www.reddit.com/r/rust
- https://users.rust-lang.org
- https://stackoverflow.com/questions/tagged/rust
- https://client00.chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
官方站點:
- https://www.rust-lang.org
- https://www.rust-lang.org/community.html
- http://blog.rust-lang.org
- https://crates.io
- http://this-week-in-rust.org
中文用戶討論區
- http://rust.cc
本文較具體的逐個介紹了Rust編程語言及其編譯器、執行時、庫、工具和社區等等核心部件,這些部件共同構成生機勃發的Rust生態系統。