Rust 從入門到精通04-變數

1、變數聲明語法

Rust 變數必須先聲明,後使用。

對於局部變數,常見是聲明語法為:

let variable : i32 = 100;

由於 Rust 是有自動推導類型功能的,所以後面的 :i32 是可以省略的。

1.1 語法解析更容易

局部變數聲明一定是以 let 開頭,類型一定是跟在冒號 : 的後面。語法歧義更少,語法分析器更容易編寫。

1.2 方便引入類型推導功能

Rust 聲明變數的特點:要聲明的變數前置,類型描述後置。
這是因為在變數聲明語句中,最重要的是變數本身,而類型其實是個附屬的額外描述,並非必不可少的部分。如果我們可以通過上下文環境由編譯器自動分析出這個變數的類型,那麼這個類型描述完全可以省略不寫。

PS:Rust 支援類型推導,在編譯器能夠推導類型的情況下,變數類型一般可以省略,但常量(const)和靜態變數(static)必須聲明類型。

Rust 從一開始就考慮了類型自動推導功能,因此類型後置的語法更加合適。

1.3 模式解構

pattern destructure
比如將變數由只讀變為可讀寫(mut聲明)

2、變數命名規則

Rust 里的合法標識符(包括變數名、函數名、trait名等)必須由:
①、數字
②、字母
③、下劃線
注意:不能以數字開頭!!!

另外:要注意下劃線 _ 的特殊用法。

3、變數遮蔽

Rust 允許在同一個程式碼塊中聲明同樣名字的變數,後面聲明的變數會將前面聲明的變數「遮蔽」起來。

//變數遮蔽
fn variable_masking(){
    let x = "123";
    println!("{}",x);

    let x = 1;
    println!("{}",x);
}

注意:這樣做並不會產生記憶體安全問題,因為我們對這塊記憶體擁有完整的所有權,且此時並沒有任何其它引用指向這個變數,對這個變數的修改是完全合法的。

4、變數類型推導

Rust的類型推導有兩種:
①、從變數聲明的當前語句中獲取資訊進行推導
②、通過上下文資訊進行推導

//類型推導
fn type_derivation(){
    //1.1 沒有明確標出變數類型,但是通過字面量的後綴,編譯器知道x的類型是 u8
    let x = 5u8;
    //1.2 通過字面量值 1,編譯器知道y 的類型是 i32
    let y = 1;

    //1.3 創建一個動態數組,但是沒有聲明數組裡面是什麼類型
    let mut vec = Vec::new();
    //編譯器通過添加的元素 1 ,推導出 vec 的實際類型是 Vec<i32>
    vec.push(1);

    println!("{}",x);
    println!("{}",y);
    println!("{:?}",vec);

}

5、類型別名

通過 type 關鍵字給同一個類型起個別名。

//類型別名
fn type_alias(){
    //將 i32 這種數據類型起別名為 int
    type int = i32;
    let x : int = 1;
    println!("{}",x);
}

類型別名還可以用於泛型場景:

type Double = (T,Vec);

那麼,以後使用 Double 的時候,就等同於(i32,Vec)

6、不可變 mut

Rust 聲明的變數默認是不可變的。

默認不可變,這是一個很重要的特性,它符合最小許可權原則,有助於我們寫出正確且健壯的程式碼。

// 變數不可變
fn variable_mut(){
    let i = 123;
    i = 2;
}

編譯報錯:

如果要使得變數可變,必須要用關鍵字 mut 聲明:

fn variable_mut(){
    let mut i = 123;
    i = 2;
}

當你使用 mut 卻沒有修改變數,Rust 編譯期會友好地報警,提示你移除不必要的 mut。

fn main() {
    variable_mut();
}
// 變數不可變
fn variable_mut(){
    let mut i = 123;
    println!("{}",i);
}

編譯器警告:

7、靜態變數

Rust 中通過 static 關鍵字聲明靜態變數,如下:

static GLOBAL : i32 = 0;

static 聲明的變數的生命周期是整個程式,從啟動到退出,static 變數的生命周期永遠是 『static』,它佔用的記憶體空間也不會在執行過程中被回收。

這也是 Rust 中唯一聲明全局變數的方法。

由於 Rust 非常注重記憶體安全,因此全局變數的使用有很多限制:
①、全局變數必須在聲明的時候馬上初始化(對應局部變數可以先聲明不初始化,只需要保證使用的時候初始化就行了,我們可以這樣理解,全局變數是寫在函數外面,而局部變數是寫在函數內部,所以需要保證全局變數聲明的時候就要初始化);
②、全局變數的初始化必須是編譯期可確定的常量,不能包括執行期才能確定的表達式、語句和函數調用;
③、帶有 mut 修飾的全局變數,在使用的時候必須使用 unsafe 關鍵字。

8、常量

Rust 中通過 const 關鍵字聲明常量。如下:

const GLOBAL : i32 = 0;

①、使用 const 聲明的是常量,而不是變數。因此不允許使用 mut 關鍵字修飾這個變數綁定。
②、常量的初始化表達式也一定要是一個編譯期確定的常量,不能是運行期的值。

注意:const 和 static 最大的區別在於編譯器並不一定會給 const 常量分配記憶體空間,在編譯過程中,它很可能會被內聯優化。

9、變數聲明常見錯誤

9.1 變數必須初始化才能使用

類型沒有默認構造函數,變數值沒有「默認值」

fn main() {
    let x : i32;
    println!("{}",x);
}

9.2 不能通過 mut 關鍵字修飾 const 聲明的變數

這個很容易理解,常量是不可變的,mut 表示可變,放一起語義衝突了。

//mut和 const 不能一起使用
fn const_mut_error(){
    const mut i : i32 = 1;
    println!("{}",i);
}