Rust從入門到精通03-變量
1、變量聲明語法
Rust 變量必須先聲明,后使用。
對(duì)于局部變量,常見是聲明語法為:
let variable : i32 = 100;
由于 Rust 是有自動(dòng)推導(dǎo)類型功能的,所以后面的 :i32 是可以省略的。
1.1 語法解析更容易
局部變量聲明一定是以 let 開頭,類型一定是跟在冒號(hào) : 的后面。語法歧義更少,語法分析器更容易編寫。
1.2 方便引入類型推導(dǎo)功能
Rust 聲明變量的特點(diǎn):要聲明的變量前置,類型描述后置。
這是因?yàn)樵谧兞柯暶髡Z句中,最重要的是變量本身,而類型其實(shí)是個(gè)附屬的額外描述,并非必不可少的部分。如果我們可以通過上下文環(huán)境由編譯器自動(dòng)分析出這個(gè)變量的類型,那么這個(gè)類型描述完全可以省略不寫。
PS:Rust 支持類型推導(dǎo),在編譯器能夠推導(dǎo)類型的情況下,變量類型一般可以省略,但常量(const)和靜態(tài)變量(static)必須聲明類型。
Rust 從一開始就考慮了類型自動(dòng)推導(dǎo)功能,因此類型后置的語法更加合適。
1.3 模式解構(gòu)
let 表達(dá)式不僅僅用于變量的綁定,還能進(jìn)行復(fù)雜變量的解構(gòu):從一個(gè)相對(duì)復(fù)雜的變量中,匹配出該變量的一部分內(nèi)容:
fn main() {
let (a, mut b): (bool,bool) = (true, false);
// a = true,不可變; b = false,可變
println!("a = {:?}, b = {:?}", a, b);
b = true;
assert_eq!(a, b);
}
2、變量命名規(guī)則
Rust 里的合法標(biāo)識(shí)符(包括變量名、函數(shù)名、trait名等)必須由:
①、數(shù)字
②、字母
③、下劃線
注意:不能以數(shù)字開頭!!!
另外:要注意下劃線 _ 的特殊用法。 如果你創(chuàng)建了一個(gè)變量卻不在任何地方使用它,Rust 通常會(huì)給你一個(gè)警告,為了去掉這個(gè)警告,可以用下劃線用作變量的開頭。
fn main() {
let _x = 5;
let y = 10;
}
運(yùn)行發(fā)現(xiàn)只有變量 y 提示警告了。

3、變量遮蔽
Rust 允許在同一個(gè)代碼塊中聲明同樣名字的變量,后面聲明的變量會(huì)將前面聲明的變量“遮蔽”起來。
//變量遮蔽
fn variable_masking(){
let x = "123";
println!("{}",x);
let x = 1;
println!("{}",x);
}

注意:這樣做并不會(huì)產(chǎn)生內(nèi)存安全問題,因?yàn)槲覀儗?duì)這塊內(nèi)存擁有完整的所有權(quán),且此時(shí)并沒有任何其它引用指向這個(gè)變量,對(duì)這個(gè)變量的修改是完全合法的。
4、變量類型推導(dǎo)
Rust的類型推導(dǎo)有兩種:
①、從變量聲明的當(dāng)前語句中獲取信息進(jìn)行推導(dǎo)
②、通過上下文信息進(jìn)行推導(dǎo)
//類型推導(dǎo)
fn type_derivation(){
//1.1 沒有明確標(biāo)出變量類型,但是通過字面量的后綴,編譯器知道x的類型是 u8
let x = 5u8;
//1.2 通過字面量值 1,編譯器知道y 的類型是 i32
let y = 1;
//1.3 創(chuàng)建一個(gè)動(dòng)態(tài)數(shù)組,但是沒有聲明數(shù)組里面是什么類型
let mut vec = Vec::new();
//編譯器通過添加的元素 1 ,推導(dǎo)出 vec 的實(shí)際類型是 Vec<i32>
vec.push(1);
println!("{}",x);
println!("{}",y);
println!("{:?}",vec);
}
5、類型別名
通過 type 關(guān)鍵字給同一個(gè)類型起個(gè)別名。
//類型別名
fn type_alias(){
//將 i32 這種數(shù)據(jù)類型起別名為 int
type int = i32;
let x : int = 1;
println!("{}",x);
}
類型別名還可以用于泛型場(chǎng)景:
type Double
= (T,Vec );
那么,以后使用 Double
6、不可變 mut
Rust 聲明的變量默認(rèn)是不可變的。
默認(rèn)不可變,這是一個(gè)很重要的特性,它符合最小權(quán)限原則,有助于我們寫出正確且健壯的代碼。
// 變量不可變
fn variable_mut(){
let i = 123;
i = 2;
}
編譯報(bào)錯(cuò):

如果要使得變量可變,必須要用關(guān)鍵字 mut 聲明:
fn variable_mut(){
let mut i = 123;
i = 2;
}
當(dāng)你使用 mut 卻沒有修改變量,Rust 編譯期會(huì)友好地報(bào)警,提示你移除不必要的 mut。
fn main() {
variable_mut();
}
// 變量不可變
fn variable_mut(){
let mut i = 123;
println!("{}",i);
}
編譯器警告:

7、靜態(tài)變量
在 Rust 中,靜態(tài)變量(Static Variables)是一種全局變量,其生命周期從程序開始直到程序結(jié)束,具有靜態(tài)的存儲(chǔ)期。
靜態(tài)變量與普通的局部變量和堆上的動(dòng)態(tài)分配變量有所不同。它們?cè)诰幾g時(shí)被初始化,并在程序的整個(gè)執(zhí)行期間保持不變。
靜態(tài)變量存儲(chǔ)在只讀的靜態(tài)數(shù)據(jù)段中,可以在整個(gè)程序的作用域內(nèi)共享和訪問。
Rust 中通過 static 關(guān)鍵字聲明靜態(tài)變量,如下:
static NAME: Type = value;
比如聲明一個(gè)靜態(tài)變量 GLOBAL:
static GLOBAL : i32 = 0;
這也是 Rust 中唯一聲明全局變量的方法。
由于 Rust 非常注重內(nèi)存安全,因此全局變量的使用有很多限制:
①、全局變量必須在聲明的時(shí)候馬上初始化(對(duì)應(yīng)局部變量可以先聲明不初始化,只需要保證使用的時(shí)候初始化就行了,我們可以這樣理解,全局變量是寫在函數(shù)外面,而局部變量是寫在函數(shù)內(nèi)部,所以需要保證全局變量聲明的時(shí)候就要初始化);
②、全局變量的初始化必須是編譯期可確定的常量,不能包括執(zhí)行期才能確定的表達(dá)式、語句和函數(shù)調(diào)用;
③、帶有 mut 修飾的全局變量,在使用的時(shí)候必須使用 unsafe 關(guān)鍵字。
8、常量
Rust 中通過 const 關(guān)鍵字聲明常量。如下:
const GLOBAL : i32 = 0;
①、使用 const 聲明的是常量,而不是變量。因此不允許使用 mut 關(guān)鍵字修飾這個(gè)變量綁定,也不允許使用 let 關(guān)鍵字。
②、常量的初始化表達(dá)式也一定要是一個(gè)編譯期確定的常量,不能是運(yùn)行期的值。
③、常量名通常約定全部字母都使用大寫,并使用下劃線分隔單詞。
④、常量聲明一定要顯式聲明類型,不能省略。否則會(huì)編譯報(bào)錯(cuò)。
const PI = 3.1415; // ? 錯(cuò)誤:missing type for `const` item
與靜態(tài)變量相比,常量有以下幾個(gè)區(qū)別:
- 不可變性:常量是不可變的,一旦初始化后就不能修改。而靜態(tài)變量可以是可變的,但在 Rust 中通常也是不可變的。
- 編譯時(shí)確定:常量的值在編譯時(shí)就被確定,并且在程序運(yùn)行時(shí)不能改變。靜態(tài)變量的值在程序運(yùn)行時(shí)也是不可變的,但它們的初始化可以包含運(yùn)行時(shí)計(jì)算的值。
- 作用域和可見性:常量的作用域可以是全局的,也可以在特定的作用域內(nèi)定義。它們可以通過使用
pub關(guān)鍵字來進(jìn)行公開,以便在其他模塊中使用。靜態(tài)變量具有全局可見性,可以在程序的任何位置訪問和使用。 - 存儲(chǔ)位置:常量通常直接嵌入到使用它們的代碼中,并不占用額外的存儲(chǔ)空間。而靜態(tài)變量存儲(chǔ)在只讀的靜態(tài)數(shù)據(jù)段中,可能占用額外的存儲(chǔ)空間。
總結(jié)來說,常量是在編譯時(shí)確定的不可變值,其值在運(yùn)行時(shí)不可修改。它們?cè)谑褂们熬捅怀跏蓟⑹冀K保持不變。常量具有諸如不可變性、編譯時(shí)確定、作用域和存儲(chǔ)位置等特性。靜態(tài)變量與常量的區(qū)別在于可變性和初始化時(shí)機(jī)等方面。
9、變量聲明常見錯(cuò)誤
9.1 變量必須初始化才能使用
類型沒有默認(rèn)構(gòu)造函數(shù),變量值沒有“默認(rèn)值”
fn main() {
let x : i32;
println!("{}",x);
}

9.2 不能通過 mut 關(guān)鍵字修飾 const 聲明的變量
這個(gè)很容易理解,常量是不可變的,mut 表示可變,放一起語義沖突了。
//mut和 const 不能一起使用
fn const_mut_error(){
const mut i : i32 = 1;
println!("{}",i);
}

9.3 使用下劃線開頭忽略未使用的變量
如果你創(chuàng)建了一個(gè)變量卻不在任何地方使用它,Rust 通常會(huì)給你一個(gè)警告,因?yàn)檫@可能會(huì)是個(gè) BUG。
但是有時(shí)創(chuàng)建一個(gè)不會(huì)被使用的變量是有用的,比如你剛剛開始創(chuàng)建一個(gè)項(xiàng)目。
如果你希望Rust 不要警告未使用的變量,可以用下劃線作為變量名的開頭:
fn main() {
let a = 5;
let _b = 6;
}

上面只有變量 a 警告了,變量 _b 沒有警告。
10、為啥要手動(dòng)設(shè)置變量可變性?
對(duì)比其它語言,比如 Java,默認(rèn)變量是可變的,如果添加 final 關(guān)鍵字,表示變量在初始化后不可再被修改。
而 Rust 中的變量默認(rèn)是不可變的。如果你想修改一個(gè)變量的值,需要在聲明時(shí)使用 mut 關(guān)鍵字顯式指定它為可變。
大概對(duì)比一下,從內(nèi)存管理來看,Java是面向?qū)ο笳Z言,內(nèi)存管理依靠垃圾收集器,程序員不需要直接管理內(nèi)存分配和釋放。而Rust 則依賴所有權(quán)和生命周期系統(tǒng)提供了無垃圾收集的內(nèi)存安全保證,編譯器通過所有權(quán)規(guī)則來保證在任何給定時(shí)間,數(shù)據(jù)要么只有一個(gè)可變引用,要么有多個(gè)不可變引用,所以默認(rèn)不可變是很有必要的。
另外,默認(rèn)聲明不可變,也會(huì)使得代碼意圖更明顯,想要修改變量,必須增加額外的操作。
默認(rèn)不可變,也可以防止數(shù)據(jù)被意外修改,rust 編譯器也能夠?qū)Σ豢勺償?shù)據(jù)進(jìn)行更多優(yōu)化,提高程序的執(zhí)行效率。
從并發(fā)上來講,如果數(shù)據(jù)不會(huì)改變,就不需要加鎖來同步訪問,因此可以避免鎖帶來的開銷和復(fù)雜性。這使得 Rust 在編寫高效且安全的并發(fā)代碼方面具有天然的優(yōu)勢(shì)。
浙公網(wǎng)安備 33010602011771號(hào)