Rust編譯器比其他語言更能捕獲隱藏的錯誤 - kerkour
讓我們看看現代編譯器和型別系統如何幫助防止許多錯誤,從而幫助提高每個人的安全性並降低軟體生產和維護的成本。
資源洩露
很容易忘記關閉檔案或連線:
resp, err := http.Get("http://kerkour.com") if err != nil { // ... } // defer resp.Body.Close() // DON'T forget this line |
另一方面,Rust 強制執行RAII(資源獲取即初始化),這使得洩漏資源幾乎是不可能的:它們在被丟棄時會自動關閉。
let wordlist_file = File::open("wordlist.txt")?; // do something... // we don't need to close wordlist_file // it will be closed when the variable goes out of scope |
未釋放的互斥鎖
看看這個 Go 程式碼:
type App struct { mutex sync.Mutex data map[string]string } func (app *App) DoSomething(input string) { app.mutex.Lock() defer app.mutex.Unlock() // do something with data and input } |
到現在為止還挺好。但是當我們想要處理許多專案時,事情可能會很快變得非常糟糕
func (app *App) DoManyThings(input []string) { for _, item := range input { app.mutex.Lock() defer app.mutex.Unlock() // do something with data and item } } |
我們剛剛建立了一個死鎖,因為互斥鎖沒有在預期的時候釋放,而是在函式結束時釋放。
同樣,Rust 中的 RAII 有助於防止未釋放的互斥鎖:
for item in input { let _guard = mutex.lock().expect("locking mutex"); // do something // mutex is released here as _guard is dropped } |
缺少Switch
假設我們正在跟蹤線上商店中產品的狀態:
const ( StatusUnknown Status = 0 StatusDraft Status = 1 StatusPublished Status = 2 ) switch status { case StatusUnknown: // ... case StatusDraft: // ... case StatusPublished: // ... } |
但是,如果我們新增了StatusArchived Status = 3變數而忘記更新這條switch語句,編譯器仍然很樂意接受程式並讓我們引入一個錯誤。
在 Rust 中,非窮舉match會產生編譯時錯誤:
#[derive(Debug, Clone, Copy)] enum Platform { Linux, MacOS, Windows, Unknown, } impl fmt::Display for Platform { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Platform::Linux => write!(f, "Linux"), Platform::Macos => write!(f, "macOS"), // Compile time error! We forgot Windows and Unknown } } } |
無效的指標取消引用
據我所知,不可能在安全的 Rust 中建立對無效地址的引用。
type User struct { // ... Foo *Bar // is it intended to be used a a pointer, or as an optional field? } |
甚至更好的是,因為 Rust 有Option列舉,你不必使用null指標來表示不存在的東西。
struct User { // ... foor: Option<Bar>, // it's clear that this field is optional } |
未初始化的變數
假設我們正在處理使用者帳戶:
type User struct { ID uuid.UUID CreatedAt time.Time UpdatedAt time.Time Email string } func (app *App) CreateUser(email string) { // ... now := time.Now().UTC() user := User { ID: uuid.New(), CreatedAt: now, UpdatedAt: now, Email: email, } err = app.repository.CreateUser(app.db, user) // ... } |
很好,但是現在,我們需要將欄位新增AllowedStorage int64到User結構中。
如果我們忘記更新CreateUser函式,編譯器仍然會愉快地接受程式碼而不做任何更改並使用int64:的預設值0,這可能不是我們想要的。
而下面的 Rust 程式碼
struct User { id: uuid::Uuid, created_at: DateTime<Utc>, updated_at: DateTime<Utc>, email: String, allowed_storage: i64, } fn create_user(email: String) { let user = User { id: uuid::new(), created_at: now, updated_at: now, email: email, // we forgot to update the function to initialize allowed_storage }; } |
產生一個編譯時錯誤,阻止我們在腳下開槍。
未處理的異常和錯誤
這聽起來可能很愚蠢,但如果你沒有異常,你就不能有未處理的異常......
panic!()Rust 中存在,但這不是處理可恢復錯誤的方式。
因此,透過強制程式設計師處理每個錯誤(或編譯器拒絕編譯程式),同時提供符合人體工程學的工具來處理錯誤(Result列舉和?運算子),Rust 編譯器有助於防止大多數(如果不是全部) ) 與錯誤處理相關的錯誤。
資料競賽
由於Sync和Send特性,Rust 的編譯器可以靜態斷言不會發生資料競爭。
它是如何工作的?您可以在Jason McCampbell的這篇精彩文章中瞭解更多資訊。
隱藏的流
在 Go 中,資料流隱藏在io.Writer介面後面。一方面,它可以簡化它們的使用。另一方面,當與我們不希望成為流的型別一起使用時,它可以保留一些驚喜,bytes.Buffer例如。
這正是一個月前發生在我身上的事情: abytes.Buffer在迴圈中被重用以呈現模板,這導致模板被附加到緩衝區而不是要清理和重用的緩衝區。
這在 Rust 中永遠不會發生,因為Streams是一種非常特殊的型別,並且永遠不會在這種情況下使用。
相關文章
- 錯誤捕獲
- 什麼情況下不要用Rust語言? - kerkourRust
- 源語言、目標語言、翻譯器、編譯器、直譯器編譯
- C語言程式碼區錯誤以及編譯過程C語言編譯
- 關於 JavaScript 錯誤捕獲JavaScript
- badamczewski/PowerUp:Rust/Go語言的反編譯工具RustGo編譯
- async和await的錯誤捕獲AI
- win10 如何隱藏語言欄_win10如何把語言欄隱藏Win10
- Flutter 錯誤捕獲的正確姿勢Flutter
- 從錯誤處理看 Rust 的語言和 Go 語言的設計RustGo
- JS 非同步錯誤捕獲二三事JS非同步
- 編譯PHP的錯誤編譯PHP
- ios交叉比編譯android錯誤解決iOS編譯Android
- 學習Rust的心智模型 - kerkourRust模型
- Ubuntu上的pycrypto給出了編譯器錯誤Ubuntu編譯
- Rust 編譯器入門Rust編譯
- C語言編譯器手機版C語言編譯
- VS 編譯錯誤編譯
- IDEA報錯java: 編譯失敗: 內部 java 編譯器錯誤IdeaJava編譯
- 解決程式碼中重複的捕獲 promise 錯誤的 try catch 語句Promise
- callback 和 promise 的錯誤捕獲-暗坑集錦Promise
- Rust中的後臺作業 - kerkourRust
- Rust 編譯器探索使用 PGORust編譯Go
- C++ 中捕獲整數除零錯誤C++
- 幽默:Go語言的編譯器 - programmerjoke9Go編譯
- ipvs編譯錯誤編譯
- php編譯小錯誤PHP編譯
- python開發-與其他語言的比較Python
- 經典的編譯錯誤 (轉)編譯
- 精讀《手寫 SQL 編譯器 - 錯誤提示》SQL編譯
- 第一個C語言編譯器是怎樣編寫的?C語言編譯
- 第一個 C 語言編譯器是怎樣編寫的?編譯
- C語言編譯工具C語言編譯
- Go 語言編譯期斷言Go編譯
- java開發C語言編譯器:為C語言提供API呼叫JavaC語言編譯API
- 使用google翻譯 api 翻譯中文成其他語言GoAPI
- Go語言內幕(2):深入 Go 編譯器Go編譯
- C 語言常用錯誤程式碼釋義大全,讓你編譯執行報錯不是煩惱編譯