搭建好了開(kāi)發(fā)環(huán)境之后,就算是正式跳進(jìn)Rust的坑了席揽,今天我就要開(kāi)始繼續(xù)向下挖了幌羞。
由于我們初來(lái)乍到 ,對(duì)Rust還不熟悉熊痴,所以我決定先走一遍常規(guī)套路聂宾。
變不變的變量
學(xué)習(xí)一門(mén)語(yǔ)言第一個(gè)要了解的當(dāng)然就是變量啦。Rust使用關(guān)鍵字let
來(lái)定義變量岭埠。我們寫(xiě)一個(gè)簡(jiǎn)單的demo
so easy惜论!等等,這個(gè)小紅線是怎么回事混聊?編譯錯(cuò)誤乾巧?沟于??別著急展懈,哪里不對(duì)點(diǎn)哪里供璧。
IDEA告訴我睡毒,這個(gè)錯(cuò)誤是
Cannot assign twice to immutable variable [E0384]
不可變的變量不能賦值兩次。我定義的變量是不可變的供搀?這能叫變量偶房?
官方文檔對(duì)此的解釋是军浆,對(duì)于一個(gè)變量乒融,你在一部分代碼中不希望它改變,而在另一部分代碼中修改了它愧捕。那么第一部分代碼的運(yùn)行結(jié)果也許就不符合預(yù)期了申钩。所以Rust的編譯器為了杜絕這種情況,也就是說(shuō)Rust的變量默認(rèn)是不可修改的邮偎。也就是說(shuō)你只能對(duì)它賦值一次禾进,之后它就是只讀的了。有點(diǎn)像Java中的final變量艇拍。嗯…很?chē)?yán)格宠纯。
但我們編程中還是需要變量的征椒,怎么辦?下面是跟著IDEA學(xué)習(xí)寫(xiě)代碼環(huán)節(jié)碍讨。直接使用Alt + Enter蒙秒,IDEA會(huì)在定義x時(shí)加上mut
關(guān)鍵字晕讲。
果然不會(huì)報(bào)錯(cuò)了瓢省。感謝IDEA。接下來(lái)運(yùn)行試試
The value of x is: 5
The value of x is: 6
打印結(jié)果符合我們的預(yù)期摹量。
mut
關(guān)鍵字在官方文檔也有解釋馒胆,定義變量時(shí)加上mut
祝迂,表明這個(gè)變量是一個(gè)可變變量。Rust之所以設(shè)計(jì)了可變變量当凡,還有一個(gè)比較重要的原因就是,對(duì)于比較復(fù)雜的數(shù)據(jù)類型粗恢,每次修改都要復(fù)制并且分配新的內(nèi)存欧瘪。這種性能損耗有時(shí)候是無(wú)法接受的佛掖。因此可以選擇使用可變變量來(lái)提高性能。
變量和常量
Rust本身也支持常量欧宜,可能大多數(shù)同學(xué)和我有一樣的疑問(wèn)拴魄,常量和不可變變量有什么區(qū)別呢匹中?
事實(shí)上它們還是有區(qū)別的。最明顯的就是名字不一樣挂绰。(這是一句廢話)
主要的區(qū)別有以下幾種:
- 定義常量時(shí)不能使用
mut
關(guān)鍵字 - 常量定義使用的關(guān)鍵字是
const
葵蒂,并且需要指定數(shù)據(jù)類型重虑。定義變量使用的是let
- 常量可以在任何范圍內(nèi)定義,并且可以在多個(gè)代碼塊中使用
- 給常量賦值時(shí)永高,不能使用函數(shù)的返回值或者是計(jì)算式乏梁。只能使用一個(gè)「常量」
變量的覆蓋
Rust是一門(mén)靜態(tài)編程語(yǔ)言关贵,對(duì)于大多數(shù)靜態(tài)編程語(yǔ)言中揖曾,在同一范圍內(nèi),變量名是不允許重復(fù)的练链。但是Rust允許這樣定義奴拦。類似于這樣:
fn main() {
let x = 5;
let x = x + 1;
let x = x + 2;
println!("The value of x is: {}", x);
}
這讓人看起來(lái)有些疑惑错妖,作為一個(gè)Java程序員,在我看來(lái)第二行就應(yīng)該報(bào)編譯錯(cuò)誤了潮模。但我們剛提到了Rust是允許這樣定義的擎厢。對(duì)于上述代碼來(lái)講辣吃,每次定義x都會(huì)覆蓋前一次定義的x。
對(duì)于Java來(lái)講沽损,將一個(gè)int類型的變量轉(zhuǎn)換成String類型的變量可能需要這樣做:
int codeInt = 1;
String codeStr = String.valueOf(codeInt);
我們需要定義兩個(gè)變量來(lái)分別接收不同類型的變量绵估,為了變量名更有意義卡骂,可能要在變量名中加上變量類型全跨。而在Rust中就不用考慮這個(gè)問(wèn)題。
let s = "123";
let s: u32 = s.parse().expect("Not a number!");
這樣定義之后渺杉,再使用變量s時(shí)挪钓,它都是u32類型的變量了碌上。
上面這個(gè)例子就是覆蓋變量和可變變量的區(qū)別:可變變量不可以修改變量類型浦徊,覆蓋變量可以做類型轉(zhuǎn)換盔性。
數(shù)據(jù)類型
可能有些同學(xué)不太理解Rust為什么是靜態(tài)語(yǔ)言呢岗。這是因?yàn)樵诰幾g階段后豫,Rust編譯器必須要明確每個(gè)變量的類型硬贯。編譯器通常會(huì)根據(jù)變量的值或者使用方法來(lái)為變量指定一個(gè)數(shù)據(jù)類型。如果某個(gè)變量可能的數(shù)據(jù)類型有多個(gè)鸵赖,那么就需要開(kāi)發(fā)者手動(dòng)指定拄衰。
像上一節(jié)的例子中翘悉,第二次定義s如果不指定類型u32,編譯就會(huì)報(bào)錯(cuò)老赤。Rust支持的數(shù)據(jù)類型都有哪些呢抬旺?
和多數(shù)編程語(yǔ)言一樣祥楣,Rust支持的數(shù)據(jù)類型可以分為基本數(shù)據(jù)類型和復(fù)合數(shù)據(jù)類型兩大類误褪。先說(shuō)基本數(shù)據(jù)類型,基本數(shù)據(jù)類型分為整數(shù)型历葛、浮點(diǎn)型啃洋、布爾型和字符型屎鳍。我們逐個(gè)介紹一下逮壁。
整數(shù)型
Rust支持的整數(shù)類型分為有符號(hào)整數(shù)和無(wú)符號(hào)整數(shù)
Length | Signed | Unsigned |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | Isize | usize |
如果沒(méi)有指定數(shù)據(jù)類型窥淆,Rust默認(rèn)使用i32
忧饭,這個(gè)類型通常是性能最好的。
再順便聊一下整數(shù)的幾種表示刺洒。
Number literals | Example |
---|---|
Decimal | 98_222 |
Hex | 0xff |
Octal | 0o77 |
Binary | 0b1111_0000 |
Byte(u8) | b'A' |
十進(jìn)制中_
一般被當(dāng)作千分符逆航。
浮點(diǎn)型
Rust的浮點(diǎn)類型不像整型那么多渔肩,它只支持兩種:f32和f64分別表示32位和64位浮點(diǎn)數(shù)周偎,默認(rèn)的浮點(diǎn)類型是f64。
布爾類型
布爾類型沒(méi)有什么特別的吧兔,Rust支持隱式和顯式聲明兩種
let t = true;
let f: bool = false;
字符型
需要注意的是字符類型char使用單引號(hào)境蔼,字符串使用雙引號(hào)伺通。字符類型的值可以是Unicode標(biāo)準(zhǔn)值罐监。范圍是從U+0000到U+D7FF和U+E000到U+10FFFF吴藻。這意味著它可以是中文韓文 emoji等等,而并不局限于直覺(jué)上的「字符」弓柱。
聊完了基本數(shù)據(jù)類型沟堡,再來(lái)聊一聊復(fù)合類型侧但,Rust包含兩種復(fù)合類型:Tuple和Array。
Tuple類型
Tuple是一種可以存儲(chǔ)不同類型的數(shù)字的集合航罗。它的長(zhǎng)度固定禀横。聲明方法是:
let tup: (i32, f64, u8) = (500, 6.4, 1);
如果想要取得tuple中的某一個(gè)值,通常有兩種方法粥血,一種是將tuple分別賦值給多個(gè)變量
fn main() {
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
println!("The value of y is: {}", y);
}
另一種方法是用直接用「.」來(lái)取值柏锄。
fn main() {
let tup = (500, 6.4, 1);
let x = tup.0;
let y = tup.1;
let z = tup.2;
println!("x: {}, y: {}, z: {}", x, y, z);
}
Array類型
Array也是多個(gè)值的集合复亏,但與Tuple不同的是趾娃,Array中的各個(gè)元素的數(shù)據(jù)類型必須相同。Array的長(zhǎng)度也是固定的缔御,這點(diǎn)上Rust的Array和其他語(yǔ)言的有所不同抬闷。Array的定義方法是:
fn main() {
let a = [1, 2, 3, 4, 5];
}
Rust的數(shù)組存儲(chǔ)在棧中,而不是堆耕突。如果你不能在定義時(shí)確定數(shù)組的長(zhǎng)度饶氏,那么需要使用vector類型,這個(gè)我們?cè)诤竺嬗懻撚泄础rray還有一些其他的定義方法疹启。
let a: [i32; 5] = [1, 2, 3, 4, 5];
i32表示數(shù)組中元素的類型,5表示元素?cái)?shù)量蔼卡。
如果初始化時(shí)所有元素的值都相同喊崖,還可以這樣定義:
let a = [3; 5];
這表示定義一個(gè)長(zhǎng)度為5的數(shù)組,每個(gè)元素都是3雇逞。
代碼寫(xiě)在哪——函數(shù)
函數(shù)在每個(gè)編程語(yǔ)言中都是基本的概念荤懂,因此我們不做過(guò)多贅述。Rust定義函數(shù)的方法是:
fn main() {
let a = 1;
let b = 2;
let sum = add(a,b);
println!("The value of sum is: {}", sum);
}
fn add(x: i32, y: i32) -> i32 {
x + y
}
Rust在定義函數(shù)時(shí)塘砸,需要指定參數(shù)的名稱和類型和返回值的類型节仿。而返回值只能是表達(dá)式。作為函數(shù)返回的表達(dá)式是不能以分號(hào)結(jié)尾的掉蔬。
該往哪走——流程控制
Rust的流程控制語(yǔ)句包括條件控制語(yǔ)句和循環(huán)語(yǔ)句廊宪。條件控制語(yǔ)句有if,循環(huán)語(yǔ)句包括loop女轿、while和for箭启。
if
Rust中if的條件必須是bool類型,它不像js中蛉迹,會(huì)自動(dòng)將變量轉(zhuǎn)換成bool類型傅寡。此外,if還可以用于let語(yǔ)句中。例如:
let number = if condition {
5
} else {
6
};
這種方式需要注意的是荐操,每個(gè)表達(dá)式中返回的值必須是同一類型的芜抒。
loop
loop循環(huán)中,如果沒(méi)有break或者是手動(dòng)停止托启,那么它會(huì)一直循環(huán)下去宅倒。寫(xiě)法很簡(jiǎn)單。
loop {
println!("again!");
}
loop的用處是它可以有返回值
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
while
while循環(huán)是當(dāng)條件成立時(shí)進(jìn)入循環(huán)驾中。
while number != 0 {
// do something
}
for
當(dāng)我們需要遍歷數(shù)組時(shí),可以使用for循環(huán)模聋。
for element in a.iter() {
println!("the value is: {}", element);
}
總結(jié)
以上肩民,是Rust的一些基本概念。和其他的編程語(yǔ)言大同小異链方,記得一些特殊的地方就好持痰,例如變量的不可變性。我們還有一些數(shù)據(jù)類型沒(méi)有涉及祟蚀,比如vector工窍,String等,這些會(huì)在后面詳細(xì)講解前酿。
至此患雏,我已經(jīng)又向下挖了一層了。不知道你入坑了沒(méi)有罢维?已經(jīng)入坑的同學(xué)還請(qǐng)麻煩幫忙往外刨(分)土(享)淹仑。
歡迎關(guān)注我的個(gè)人公眾號(hào):代碼潔癖患者