Rust使用感受

一、關於內存管理

1、rust加入了生命週期和所有權的特性,實現內存自動回收,避免內存泄漏和野指針的問題。

例如:,局部變量離開作用域後Rust會連同變量綁定的內存,不管是否爲常量字符串,連同所有者變量一起被銷燬釋放。所以上面的例子,a銷燬後再次訪問a就會提示無法找到變量a的錯誤。

這些所有的一切都是在編譯過程中完成的。

2、Rust沒有null,取而代之的是None和Option<T>,且Rust並不會像其他語言一樣可以爲變量默認初始化值,Rust明確規定變量的初始值必須由程序員自己決定。

例如:如果a不初始化,則會產生如下錯誤:

3、移動語義的概念

Rust的移動語義和C++11標準中的移動語義類似,都是可以解決內存多次釋放造成系統崩潰問題。但是Rust的概念稍微有些特殊,來個例子

編譯之後會得到如下的錯誤:

 

編譯信息可以看出編譯器會做儘可能多的檢查,爭取在編譯發現問題,且編譯信息友好,有的問題直接就你提示,告你怎麼修改會程序編譯。(缺點就是編譯時間~~~)

先看紅色的編譯提示    第三個    錯誤的意思是在println中訪問了被moved的變量a 在Rust中,有個機制叫做“轉移move所有權”,意思是,可以把資源的所有權(ownership)從一個綁定a轉移(move)成另一個綁定b,被move的變量a不可以繼續被使用。

還有一個問題,move後,如果變量a和變量b離開作用域,所對應的內存會不會造成“C++經常遇到的2次釋放”的問題?不會的,只有資源的所有者銷燬後才釋放內存,而無論這個資源是否被多次move,同一時刻只有一個owner(有點類似C++11中的 unique_ptr)所以該資源的內存也只會被釋放一次。通過這個機制,就保證了內存安全。

 

我們再看    第一個    的警告提示,在Rust中,如果定義了一個未被使用的變量,是需要給用戶提示警告信息,並告訴用戶如果想消除此警告信息,例如圖中所示,加個”_”即可,但是在實際編程中,未被使用的變量是不會讓其存在的。

再看   第二個錯誤     在Rust中String類型是沒有實現Copy特性的,如果將上面的代碼中的a改成i32類型,就可以編譯通過,因爲i32實現了Copy特性,在move時會拷貝資源到新的內存區域,move前後的a和b對應資源內存的地址不同。(Rust中,基本數據類型均實現了Copy特性)

 

二、關於Future

1、什麼是Future,可以理解成一種不會立即執行的古怪函數,他會在未來被執行(future名字的由來?)我們可以利用Future,將邏輯異步轉成同步的代碼,通過and_then將各個future串聯起來,將來依次執行,所以,我們在多線程開發過程中,只需要關心future怎麼寫,怎麼傳遞。缺點是代碼可讀性不高,通篇都是and_then,腦袋大。

在future的串聯過程中,把一個future的返回值傳給下一個future的部分有點棘手,在Rust中,我們使用閉包參數來捕獲(Rust的閉包有點類似於C++11標準中的lambda表達式)。

 

2、麻煩的Error,把future連接起來並不困難,但是他們的錯誤類型必須都要匹配上去才行,即鏈式futures的錯誤類型必須要統一,否則編譯不過!這也是我開發過程中遇到最多的編譯錯誤問題。這就引出了From的概念

單獨舉個小例子:

假設我們已經定義了兩個錯誤類型ErrorA和ErrorB

fn fut_error_a() -> impl Future<Item = (), Error = ErrorA> {

    err(ErrorA {})

}

fn fut_error_b() -> impl Future<Item = (), Error = ErrorB> {

    err(ErrorB {})

}

然後把他倆串起來

let future = fut_error_a().and_then(|_| fut_error_b());

編譯之後出現錯誤   

    |     let future = fut_error_a().and_then(|_| fut_error_b());

    |                                ^^^^^^^^ expected struct `errors::ErrorB`, found struct `errors::ErrorA`

    |

    = note: expected type `errors::ErrorB`

               found type `errors::ErrorA`

我們在本該有ErrorB的地方得到一個ErrorA,

我們可以利用std::convert::From trait,使用From,可以告訴Rust怎麼全自動從元類型轉成目標類型

impl From<ErrorB> for ErrorA {

    fn from(e: ErrorB) -> ErrorA {

        ErrorA::default()

    }

}

impl From<ErrorA> for ErrorB {

    fn from(e: ErrorA) -> ErrorB {

        ErrorB::default()

    }

}

 

let future = fut_error_a().map_err(|e| ErrorB::from(e)).and_then(|_| fut_error_b());

這樣的話,錯誤類型一致,編譯錯誤取消。

在開發中,最好單獨有個error.rs的文件,專門去做錯誤類型轉換的功能。

三、項目構建

爲了解決C/C++項目的管理問題 ,開發出了cmake    、qmake等項目管理工具,但結果並不如人意, C/C++er經常會陷入在掌握語言本身的同時,還要掌握複雜的構建工具語法的窘境。作爲rust的代碼組織管理工具,cargo提供了一系列的工具,從項目的建立、構建到測試、運行直至部署,爲rust  項目的管理提供儘可能完整的手段。

其中說一下最重要的cargo.toml文件。

 

基於git倉庫地址,通過URL來描述

基於Rust官方倉庫crates.io,通過版本說明來描述

 

[package]: 描述了軟件開發者對本項目的各種元數據描述信息,項目名稱、版本、作者等等

[dependencies]:描述該項目的各種依賴項

 

四、其它

代碼裏禁止出現expect(),unwrap()函數。取而代之用默認值,或者修改類型(不用Option,Result)

總之:一句話總結Rust和C++的區別,我的想法就是:

rust:編譯時想撞牆。
c++:調試時想跳樓。

發佈了23 篇原創文章 · 獲贊 37 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章