Rust能力養成之(1):與眾不同的初始化

海資料實驗室發表於2020-12-29

圖片

 

前言

之前寫過了三篇介紹Rust語言的文章(樣樣精通的Rust與其內功心法),想必大家也都認識到該語言的能力,用途,以及前景之光明瞭,於是自本文起,筆者開始著力撰寫一個自下而上的培養rust程式設計能力的文字系列。

在此很感謝相關老師,朋友的支援,讓我有動力進行這方面內容的寫作,同時也期待讀者朋友們於日後的積極互動,以令這方面的內容達到最佳優化,那麼,一個教學互長的歷程便由此開展。

從這裡開始,讓我們從零開始學習Rust。

 

本文將介紹

  • Rust的安裝與編譯

  • Rust基本資料型別

  • 變數宣告和不可變繫結

Rust的安裝與編譯

安裝

就安裝方式而言,推薦使用rustup,無論是新裝,升級還是降低版本都很便利。Windows系統的話,可以下載如下的exe檔案:

(https://www.rust-lang.org/tools/install)

圖片

如果是linux系統可以終端鍵入如下命令

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

餘下步驟按照提示即可。

圖片

開發環境

本文大部分程式碼都在Windows10環境下使用vscode編輯器完成。

圖片

編譯

在rust中,通常有兩種編譯方式

  • 第一,對於單獨指令碼,使用rustc filename.rs

  • 第二,在工程管理視野下,使用cargo run(後續會詳談)

     

本文中,為了便於演示,是在vscode中,新增了rust-analyerrun code外掛,通過滑鼠點選進行編譯並檢視結果,這應該是很符合入門級別的習慣。

圖片

 

當然,許多小程式碼檔案,可以到playground去跑一下

https://play.rust-lang.org/

圖片

第一闕程式碼

為了避免俗套,就不寫Hello World!了,我們看以下程式碼(greet.rs)。在Rust中,所有程式碼都以 fn main(){}開始寫起。

//greet.rsuse std::env;fn main() {   let name = env::args().skip(1).next();   match name {        Some(n) => println!("Hi there ! {}", n),        None => panic!("Didn't receive any name ?"),    }}

解釋程式碼

  • 行2:從標準庫std crate(在rust中,庫-library,被稱為crate)中匯入模組(module)env

  • 行4:呼叫env中的args()函式,以返回一個迭代器性質的引數序列,

    • 由於序列的第一個引數包含路徑的資訊,沒必要在這裡顯示,就利用skip(1)跳過該引數,

    • 由於迭代器是惰性的,不會預先計算,需要用next()來指定。

      • next()返回一個列舉型別(enum type)的稱為Option選項的量

      • 這個量會與後續的Some(value)的值或者None的值相對應。

  • 行5:match 是rust中很讚的表示式,類似於C中的switch-case,用於判斷是否name在以下的語句中存在,

  • 行6:當Some(n),也就是存在一些值時,把值傳給n,呼叫println!,顯示所謂的greet結果,

    • println!,有歎號,可見是個巨集(macro),不是函式

  • 行7:表明如果返回的列舉型別是none,則呼叫 panic!,進行報錯。

程式碼結果

圖片

 

談一下println!巨集

 

從以上程式碼可見,該巨集接收字串,並予以顯示。

這裡有些格式問題,需要談一下:如果顯示的資料型別為基本資料型別(primitives),使用大括號"{}";如果是其他資料型別使用"{:?}"

前者涉及Display特性(trait),後者涉及Debug特性(這意味著有時候需要 #[derive(Debug)] 屬性,當該方法有時並未為某些型別具備時)。

此處劇透一下,涉及這方面詳細內容,會在後續的源語言程式設計(Metaprogramming with Macros)中介紹。

 

基本資料型別(Primitive types)

 

這裡給出rust的內建基本資料型別,大家可以同其他語言進行對照,不難理解。

  • 布林,bool

  • 字串,char

  • 整型,目前支援到128bits,具體有:

圖片

  • isize:32-bit 或者 64-bit的帶符號整形指標

  • usize:32-bit 或者 64-bit的無符號整形指標

  • f32:32-bit浮點

  • f64:64-bit浮點

  • [T; N], 定長陣列,T為資料型別,N為長度或者規格(size)

  • str:字串,通常使用其引用&str

  • (T, U,..): 有限序列,T and U 可以是不同型別

  • fn(i32) -> i32: 是一個函式,這裡該函式輸入型別為i32,返回值型別為i32;以此可見,函式的型別也有了明確而顯式的定義

 

變數宣告與不可變繫結

(Declaring variables and immutability)

 

在Rust中,使用let關鍵詞來宣告變數。在時下一些主流的命令式語言(imperative language)中,如C或Python,初始化一個變數不會影響你在下一步中重新對其賦值。

然而,Rust在這裡與主流分道揚鑣,這意味著,如果你已經為一個變數初始化,則不能再把該變數賦予其他的值。

但如果你還是需要將一個變數賦予新值,則需用使用mut關鍵字。這裡就體現出Rust的一個特色,那就是儘可能讓你在程式設計時思路清晰。

我們看以下程式碼,其中target 是不可變繫結,greeting是可變繫結。第7行中,target被重新賦值為mate。

//variables.rs fn main() {    let target = "world"; //no mut    let mut greeting = "Hello";    println!("{}, {}", greeting, target);    greeting = "How are you doing";    target = "mate";    println!("{}, {}", greeting, target);}

從下面結果看來,沒有編譯成功,原因是,不能為不可變繫結變數賦值兩次

圖片

 

於是,在第2行 為變數target加上mut,如下所示。

fn main() {    let mut target = "world"; //add mut    let mut greeting = "Hello";    println!("{}, {}", greeting, target);    greeting = "How are you doing";    target = "mate";    println!("{}, {}", greeting, target);}
編譯成功,結果表明以上的兩個可變繫結,都獲得了各自的二次賦值。

圖片

 

結語

 

希望讀者朋友這裡注意一下,不可變繫結和可變繫結在Rust中具有重要地位,事關安全效率等問題,後續篇章會著重論述。

本文從零開始,引入了一些Rust的基本元素和適當的程式碼,並沒有實行快速行進的教程方式,因為該語言雖然也沒有C那麼難學,也並不像Python那麼容易學習,但本著先練好基本功的原則,開始階段,會採取慢慢講的方式。

當然,對讀者還是有些要求,希望最好能夠了解一種以上的主流程式語言,如C或Python,這樣更容易進入狀態。

下一篇,會開始講一下函式。

 

 

主要參考和建議讀者進一步閱讀的文獻

https://doc.rust-lang.org/book

1.Rust程式設計之道,2019,張漢東

2.The Complete Rust Programming Reference Guide,2019,Rahul Sharma,Vesa Kaihlavirta,Claus Matzinger

3.Hands-On Data Structures and Algorithms with Rust,2018,Claus Matzinger

4.Beginning Rust ,2018,Carlo Milanesi

5.Rust Cookbook,2017,Vigneshwer Dhinakaran

 

相關文章