Rust 從入門到精通04-變量

Rust 變量必須先聲明,后使用。 ?
對(duì)于局部變量,常見是聲明語(yǔ)法為: ?
let variable : i32 = 100; ?
由于 Rust 是有自動(dòng)推導(dǎo)類型功能的,所以后面的 :i32 是可以省略的。
1.1 語(yǔ)法解析更容易 ?
局部變量聲明一定是以 let 開頭,類型一定是跟在冒號(hào) : 的后面。語(yǔ)法歧義更少,語(yǔ)法分析器更容易編寫。 ?
1.2 方便引入類型推導(dǎo)功能
Rust 聲明變量的特點(diǎn):要聲明的變量前置,類型描述后置。 ? 這是因?yàn)樵谧兞柯暶髡Z(yǔ)句中,最重要的是變量本身,而類型其實(shí)是個(gè)附屬的額外描述,并非必不可少的部分。如果我們可以通過(guò)上下文環(huán)境由編譯器自動(dòng)分析出這個(gè)變量的類型,那么這個(gè)類型描述完全可以省略不寫。
PS:Rust 支持類型推導(dǎo),在編譯器能夠推導(dǎo)類型的情況下,變量類型一般可以省略,但常量(const)和靜態(tài)變量(static)必須聲明類型。 ?
Rust 從一開始就考慮了類型自動(dòng)推導(dǎo)功能,因此類型后置的語(yǔ)法更加合適。 ?
1.3 模式解構(gòu)
pattern destructure ? 比如將變量由只讀變?yōu)榭勺x寫(mut聲明) ?
2、變量命名規(guī)則
Rust 里的合法標(biāo)識(shí)符(包括變量名、函數(shù)名、trait名等)必須由: ? ①、數(shù)字 ? ②、字母 ? ③、下劃線 ? 注意:不能以數(shù)字開頭?。。??
另外:要注意下劃線 _ 的特殊用法。 ?
3、變量遮蔽 ?
Rust 允許在同一個(gè)代碼塊中聲明同樣名字的變量,后面聲明的變量會(huì)將前面聲明的變量“遮蔽”起來(lái)。 ?
?//變量遮蔽
?fn variable_masking(){
? ? ?let x = "123";
? ? ?println!("{}",x);
?
? ? ?let x = 1;
? ? ?println!("{}",x);
?}

注意:這樣做并不會(huì)產(chǎn)生內(nèi)存安全問(wèn)題,因?yàn)槲覀儗?duì)這塊內(nèi)存擁有完整的所有權(quán),且此時(shí)并沒有任何其它引用指向這個(gè)變量,對(duì)這個(gè)變量的修改是完全合法的。
4、變量類型推導(dǎo)
Rust的類型推導(dǎo)有兩種: ? ①、從變量聲明的當(dāng)前語(yǔ)句中獲取信息進(jìn)行推導(dǎo) ? ②、通過(guò)上下文信息進(jìn)行推導(dǎo) ?
?//類型推導(dǎo)
?fn type_derivation(){
? ? ?//1.1 沒有明確標(biāo)出變量類型,但是通過(guò)字面量的后綴,編譯器知道x的類型是 u8
? ? ?let x = 5u8;
? ? ?//1.2 通過(guò)字面量值 1,編譯器知道y 的類型是 i32
? ? ?let y = 1;
?
? ? ?//1.3 創(chuàng)建一個(gè)動(dòng)態(tài)數(shù)組,但是沒有聲明數(shù)組里面是什么類型
? ? ?let mut vec = Vec::new();
? ? ?//編譯器通過(guò)添加的元素 1 ,推導(dǎo)出 vec 的實(shí)際類型是 Vec<i32>
? ? ?vec.push(1);
?
? ? ?println!("{}",x);
? ? ?println!("{}",y);
? ? ?println!("{:?}",vec);
?
?}
5、類型別名
通過(guò) 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> = (T,Vec<T>); ?
那么,以后使用 Double<i32> 的時(shí)候,就等同于(i32,Vec<i32>) ?
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 中通過(guò) static 關(guān)鍵字聲明靜態(tài)變量,如下: ?
static GLOBAL : i32 = 0; ?
static 聲明的變量的生命周期是整個(gè)程序,從啟動(dòng)到退出,static 變量的生命周期永遠(yuǎn)是 ‘static’,它占用的內(nèi)存空間也不會(huì)在執(zhí)行過(guò)程中被回收。 ?
這也是 Rust 中唯一聲明全局變量的方法。
由于 Rust 非常注重內(nèi)存安全,因此全局變量的使用有很多限制: ? ①、全局變量必須在聲明的時(shí)候馬上初始化(對(duì)應(yīng)局部變量可以先聲明不初始化,只需要保證使用的時(shí)候初始化就行了,我們可以這樣理解,全局變量是寫在函數(shù)外面,而局部變量是寫在函數(shù)內(nèi)部,所以需要保證全局變量聲明的時(shí)候就要初始化); ? ②、全局變量的初始化必須是編譯期可確定的常量,不能包括執(zhí)行期才能確定的表達(dá)式、語(yǔ)句和函數(shù)調(diào)用; ? ③、帶有 mut 修飾的全局變量,在使用的時(shí)候必須使用 unsafe 關(guān)鍵字。
8、常量
Rust 中通過(guò) const 關(guān)鍵字聲明常量。如下: ?
const GLOBAL : i32 ?= 0; ?
①、使用 const 聲明的是常量,而不是變量。因此不允許使用 mut 關(guān)鍵字修飾這個(gè)變量綁定。 ? ②、常量的初始化表達(dá)式也一定要是一個(gè)編譯期確定的常量,不能是運(yùn)行期的值。 ?
注意:const 和 static 最大的區(qū)別在于編譯器并不一定會(huì)給 const 常量分配內(nèi)存空間,在編譯過(guò)程中,它很可能會(huì)被內(nèi)聯(lián)優(yōu)化。
9、變量聲明常見錯(cuò)誤
9.1 變量必須初始化才能使用
類型沒有默認(rèn)構(gòu)造函數(shù),變量值沒有“默認(rèn)值”
?fn main() {
? ? ?let x : i32;
? ? ?println!("{}",x);
?}

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