Rust编程语言的核心部件
Rust是一門強調安全、并發、高效的系統編程語言。無GC實現內存安全機制、無數據競爭的并發機制、無運行時開銷的抽象機制,是Rust獨特的優越特性。它聲稱解決了傳統C語言和C++語言幾十年來飽受責難的內存安全問題,同時還保持了很高的運行效率、很深的底層控制、很廣的應用范圍,在系統編程領域具有強勁的競爭力和廣闊的應用前景。
\\從狹義的角度說,Rust編程語言,就是其語言本身,一份以人類語言描述的計算機編程語言的規范文檔。然而單單語言本身,僅具有理論價值;要發揮其實用價值,往往還要有編譯器、標準庫、運行環境等一系列配套設施,共同組成一套完整的生態體系。
\\從廣義的角度說,Rust編程語言包括了:語言規范(reference)、編譯器(rustc)、運行時(runtime)、標準庫(std)、核心庫(core)、庫(crates)、包管理器(cargo)、社區(communities)等等。
\\本文將詳細介紹廣義上的Rust編程語言之各個組成部分。
\\語言規范
\\Rust語言規范規定了Rust編程語言的語法和語義。跟其他語言規范一樣,充滿枯燥的文字,真正愿意通讀下來的人很少。大多數人通過初級教程學習語言的基本語法和語義,僅在必要時翻閱或查閱語言規范的局部內容。不過嚴格來說,Rust目前提供的這份文檔并不算是語言規范(specification),而僅僅只是參考文檔。
\\編譯器(rustc)
\\官方的rustc是目前唯一的Rust編譯器(之前的rustboot編譯器早就被廢棄了),它負責把Rust源代碼編譯為可執行文件、Rust庫(crates)或其他庫文件(.a/.lib/.so/.dll)。
\\- rustc是跨平臺的應用程序,其可執行文件名是 rustc (for Unix/Linux/...) 或 rustc.exe (for Windows),最基本的命令行調用方法是 rustc hello.rs。\\t
- rustc具有交叉編譯功能,可以在當前平臺下編譯出可運行于其他平臺的應用程序和庫(但需要事先編譯或安裝目標平臺的工具鏈)。\\t
- rustc采用LLVM作為編譯器后端,具有很好的代碼生成和優化技術,支持許多目標平臺。\\t
- rustc目前使用gcc作為鏈接器(同時也運行時依賴glibc運行庫,今后可換用MUSL靜態庫,相關開發工作在進行中);今后在Windows平臺將支持使用MSVC作為鏈接器(相關開發工作在進行中)。\\t
- rustc編譯出來的程序,支持用GDB和LLDB調試運行。用戶不需要更換自己已經熟悉的調試工具,Rust沒有也不需要自己專屬的調試器。\\t
- rustc是用Rust語言開發的,并且是開源的,最新源代碼在這里。https://github.com/rust-lang/rust/tree/master/src/librustc\
運行時(runtime)
\\在沒有明確上下文的情況下,運行時(runtime)通常可被理解為“運行時庫(runtime library)”或“運行時損耗(runtime overhead)”。下面就這兩種情況分別闡述,最后得出的結論是:Rust可以沒有運行時庫,且僅有很小的運行時損耗。
\\運行時庫(runtime library)
\\編程語言的運行時庫,通常理解為,其編譯出的可執行程序在運行時必須依賴的非操作系統本身的動態庫。例如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環境嗎?做夢。沒有了運行時庫,程序的所有代碼都是程序員可控的(至于標準庫的影響,下文將會談到)。
\\(更寬泛地說,運行時庫居無定形,未必一定以獨立動態庫的形式存在,它也可能隱身于標準庫甚至是可執行文件內部。只要它給程序本身帶來了額外的且無法消除的明顯的依賴和不可忽略的運行時損耗,我們就通通認為它是運行時(庫)。反過來說,如果運行時(庫)的運行時損耗小到一定程度,且沒有帶來額外的運行時依賴,我們甚至可以認為它不是運行時(庫)。此中斟酌,見仁見智。)
\\運行時損耗(runtime overhead)
\\程序的運行時損耗,是指程序在運行過程中所必須付出的額外的代價。例如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的虛擬機和垃圾收集器,顯然是突出的運行時損耗。
\\標準庫(std)
\\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生態系統的基石。如果標準庫不提供這些類型,讓第三方庫各行其是的話,整個生態系統將很難形成合力。\\t - 基礎類型操作接口
\\t如 bool, char, i8/u8, i16/u16, i32/u32, i64/u64, isize/usize, f32/f64, str/array/slice/tuple/pointer 等基礎類型數據的操作接口及其實現。\\t - 常用的功能性數據類型
\\t如 String, Vec, HashMap, Rc, Arc, Box, CString, OsString, SipHasher 等等。滿足常見的、常用的,或特定的功能需求。\\t - 常用的宏定義
\\t如 println!, format!, assert!, try!, panic!, vec!, thread_local!, file!, line!, include! 等等。基礎的或核心的宏。其中某些宏是借助編譯器實現的。\\t - 跨平臺的I/O相關的系統功能
\\t如 std::io, std::fs, std::path, std::env, std::process 等等。\\t - 跨平臺的網絡/多線程/同步相關系統功能
\\t如 std::net, std::thread, std::sync 等等。\\t - 其他的不跨平臺的操作系統相關功能
\\t如 std::os,為各主流操作系統分別提供了專門的操作接口,便于實現系統特有的功能調用。\\t - 底層操作接口
\\t如 std::mem, std::ptr, std::intrinsics 等,操作內存、指針、調用編譯器固有函數。\\t - 其他\
核心庫(core)
\\Rust核心庫,可以理解為是經過大幅精簡的標準庫,它被應用在標準庫不能覆蓋到的某些少數特定領域,如嵌入式開發。
\\前面提到過,標準庫應用范圍很廣,為絕大多數應用程序提供支持。但是在嵌入式開發、操作系統開發、裸金屬(bare metal)環境下,標準庫就無能為力了。主要有以下兩個原因導致標準庫的應用范圍受到一定的限制:
\\- 標準庫的“跨平臺”是指“跨主流操作系統平臺”,也就是跨 Windows、Unix/Linux、Mac/OSX 等少數幾個操作系統。標準庫內有相當數量的API(如文件、網絡、多線程等)必須依賴操作系統提供的接口,到了非主流系統尤其是嵌入式系統環境下,標準庫失去了底層系統的支撐根本就不可能工作。\\t
- 標準庫內有相當數量的API(如String/Vec、Box、panic等)依賴內存申請和釋放功能,但是在操作系統開發、裸金屬(bare metal)環境下,要么不存在這些功能,要么需要自己開發。\
這些限制對Rust標準庫來說其實并不是問題,跟世界上大多數編程語言的標準庫一樣,為主流系統的主流應用開發提供豐富的功能支持,才是最重要的。如果單純為了提升應用范圍砍掉操作系統相關的功能,那標準庫也大概成了空殼子,功能性和實用性大打折扣,徹底失去了標準庫的價值——誰能接受一個連文件、網絡、多線程功能都沒有的標準庫呢?
\\Rust的選擇是,在標準庫之外,再單獨提供一個核心庫,重點應對嵌入式應用開發。核心庫不依賴任何操作系統,也不提供文件/網絡/多線程/內存申請釋放相關的任何功能,因而可移植性更好、應用范圍更廣。當用Rust開發一個操作系統或硬件驅動或嵌入式應用時,你總不能指望去調用別的主流操作系統接口吧?那顯然是不切實際的。所以對核心庫來說,它缺少的那些OS相關功能原本就是多余的。
\\在代碼開頭寫上 #![no_std] 就代表放棄標準庫,而使用核心庫。核心庫里面有:基礎的接口性數據類型(參見上文,下同)、基礎類型操作接口、常用的功能性數據類型、常用的宏定義、底層操作接口等,而且跟標準庫API幾乎是完全一致的;再配合alloc庫(或自己定制的alloc庫)又有了內存申請釋放功能;再加上collections庫,String/Vec/HashMap等也有了。事實上從內部實現來說,標準庫里的某些功能正是來源于核心庫(以及alloc/collections等)。
\\庫(crate)
\\把多個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)
\\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是一個令人驕傲的優秀工具。而且它不僅是一個工具,更是一個生態系統。
\\社區(communities)
\\Rust有相當龐大的社區。僅參與開發Rust系統本身的開發者就多達1300人,并持續增長,這類開發者中,以Mozilla公司員工組成的約10人團隊為核心,以來自世界各地的貢獻者為輔助。采用Rust開發應用的開發者人數更多,但難以統計數量。當然,作為新興語言,Rust社區規模相對Java、Python社區而言還稚嫩的很,發展潛力無限。
\\Rust開發者活動軌跡主要集中在Github網站、IRC在線聊天室、Reddit論壇和Rust官方論壇中。此外,圍繞某些頗具雄心的項目還各自形成了獨立子社區,如Servo、Piston、MaidSafe、Redox等。
\\源代碼倉庫、設計開發討論區:
\\- https://github.com/rust-lang/rust\\t
- https://github.com/rust-lang/rfcs\\t
- https://github.com/rust-lang/cargo\\t
- https://internals.rust-lang.org\\t
- https://client00.chat.mibbit.com/?server=irc.mozilla.org\u0026amp;channel=%23rustc\
用戶應用討論提問區:
\\- https://www.reddit.com/r/rust\\t
- https://users.rust-lang.org\\t
- https://stackoverflow.com/questions/tagged/rust\\t
- https://client00.chat.mibbit.com/?server=irc.mozilla.org\u0026amp;channel=%23rust\
官方網站:
\\- https://www.rust-lang.org\\t
- https://www.rust-lang.org/community.html\\t
- http://blog.rust-lang.org\\t
- https://crates.io\\t
- http://this-week-in-rust.org\
中文用戶討論區
\\- http://rust.cc\
總結
\\本文依次介紹了Rust編程語言及其編譯器、運行時、庫、工具和社區等核心部件,它們共同構成了生機勃發的Rust生態系統。
總結
以上是生活随笔為你收集整理的Rust编程语言的核心部件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Matlab Command Windo
- 下一篇: 新机房测试流程