Rust 從入門到精通06-語句和表達式
1、語句和表達式
語句和表達式是 Rust 語言實現(xiàn)邏輯控制的基本單元。 在 Rust 程序里面,語句(Statement)是執(zhí)行一些操作但不返回的指令,表達式(Expressions)計算并產(chǎn)生一個值。表達式可以是語句的一部分,反過來,語句也可以是表達式的一部分。
1.1 語句不返回值
fn?main()?{
????let?x?=?(let?y?=?6);
}
這里面let y = 6
是一個語句,不能把 let
語句賦值給另一個變量,否則編譯器會報錯。
1.2 表達式返回值
fn?main()?{
????let?y?=?{
????????let?x?=?3;
????????x?+?1
????};
????println!("The?value?of?y?is:?{}",?y);
}
{}
,也是一個表達式,表達式的結(jié)果是最后一行代碼,x + 1
后面沒有分號,表示的是表達式,如果在表達式后面加上“;”,則表示語句,語句沒有返回值,則上面代碼會報錯。
1.3 總結(jié)
①、一個表達式總會產(chǎn)生一個值,因此它必然有類型。 ②、語句不產(chǎn)生值,它的類型永遠是 (); ③、如果把一個表達式加上分號,那么它就變成了一個語句; ④、如果把一個語句放到一個語句塊中包起來,那么它就可以當成一個表達式使用。
Rust is primarily an expression language
翻譯過來:Rust 基本上就是一個表達式語言。
Rust 除了 let / static / const / fn 等少數(shù)語句外,Rust 絕大多數(shù)代碼都是表達式(expression)。所以 if / while / for / loop 都會返回一個值,函數(shù)最后一個表達式就是函數(shù)的返回值,這和函數(shù)式編程語言一致。
語句就是計算結(jié)果為()的特殊表達式。Rust 編譯器,在解析代碼的時候,如果碰到分號,就會繼續(xù)往后執(zhí)行。如果遇到語句,就執(zhí)行語句;如果遇到表達式,則會對表達式求值;如果分號后面什么都沒有,就補上()。
2、算術(shù)表達式
2.1、算術(shù)運算符:+ - * / %
分別是加、減、乘、除、取余。
//加、減、乘、除、取余
fn?arithmetic_operation_test1(){
????let?x?=?100;
????let?y?=?10;
????println!("x={},y={},x+y={},x-y={},x*y={},x/y={},x%y={}",x,y,x+y,x-y,x*y,x/y,x%y);
}
2.2、比較運算符
注意: ①、比較運算符兩邊必須是同類型的,并且滿足 PartialEq 約束; ②、比較表達式的類型是 bool; ③、Rust 禁止連續(xù)比較;
fn?compare_test(a:bool,b:bool,c:bool)?->?bool{
????a==b==c
}
編譯報錯:

2.3、賦值表達式
一個左值表達式、賦值運算符(=)、一個右值表達式可以構(gòu)成一個賦值表達式。 ①、賦值號左右兩邊表達式的類型必須一致,否則編譯報錯。 ②、賦值表達式也有對應(yīng)的類型和值,類型為 unit。即空的 tuple();
//賦值表達式也有對應(yīng)的類型和值,類型為?unit
fn?arithmetic_operation_test2(){
????let?x?=?1;
????let?mut?y?=?2;
????let?z?=?(y=x);
????//打印結(jié)果為()
????println!("{:?}",z);
}
這樣能防止連續(xù)賦值,假設(shè)定義了三個 i32 類型的變量, x:i32,y:i32以及z:i32, 那么表達式 x=y=z就會發(fā)生編譯錯誤,因為z變量是i32類型,卻賦值(),編譯器是不允許的。
2.4、語句塊表達式
在Rust 中,語句塊也可以是表達式的一部分。
語句和表達式的區(qū)分方式是后面帶不帶分號,如果帶了分號,意味著這是一條語句,它的類型是();
如果沒有帶分號,它的類型就是表達式的類型。
//語句和表達式的區(qū)分方式是后面帶不帶分號,如果帶了分號,意味著這是一條語句,它的類型是();
//如果沒有帶分號,它的類型就是表達式的類型。
fn?arithmetic_operation_test3(){
????//語句帶分號,類型是?()
????let?x:()?=?{println!("helloworld");};
????//Rust?將按照順序執(zhí)行語句塊內(nèi)的語句,并將最后的一個表達式類型返回,所以?y?最終類型是?i32
????let?y?=?{println!("helloworld");?5};
????println!("x={:?}",x);
????println!("y={}",y);
}
打印結(jié)果為:

2.5、if-else
①、條件表達式的類型必須是bool ②、條件表達式并未強制要求用小括號()括起來,如果括起來,編譯器反而會告警,認為是多余的括號; ③、后面的結(jié)果語句塊一定要用大括號括起來;
//if-else
fn?if_else_test()->i32{
????if?(1>2)?{
????????//沒有加分號,返回值就是1
????????1
????}else{
????????2
????}
}
使用 if-else 作為表達式,一定要注意 if 和 else 分支的類型必須一致,否則就不能構(gòu)成一個合法的表達式,會出現(xiàn)編譯錯誤。
最常見的一種情況是 if 分支有數(shù)據(jù)返回,但是省略了 else 分支:
fn?if_test()?->?i32{
????if?true?{
????????1
????}
????return?1;
}
編譯報錯:
這是因為 else 分支如果省略了,默認類型是 ’()‘ ,與 if 分支不匹配。

2.6、loop
在Rust中,loop表示無限死循環(huán)。
//loop
fn?loop_test(){
????let?mut?i?=?0;
????loop{
????????i?+=?1;
????????if(i?==?3){
????????????println!("three");
????????????//不在繼續(xù)執(zhí)行后面的代碼,直接跳轉(zhuǎn)到loop開頭繼續(xù)循環(huán)
????????????continue;
????????}
????????println!("{}",i);
????????if(i?==?5){
????????????println!("that's?is?OK");
????????????//跳出循環(huán)
????????????break;
????????}
????}
}
continue 表示本次循環(huán)內(nèi),不在執(zhí)行后面的語句,直接進入下一輪循環(huán); break 表示跳出循環(huán),不在執(zhí)行。
注意:在Rust中,我們可以在 loop、while、for循環(huán)前面加上“生命周期標識”,在內(nèi)部循環(huán)中,可以通過break、continue選擇跳轉(zhuǎn)到哪個循環(huán)標識。
2.7、while
帶條件判斷的循環(huán)語句。
//while循環(huán)
fn?while_test(){
????let?mut?n?=?1;
????while(n?<?100){
????????if(n%2==0){
????????????println!("偶數(shù):{}",n)
????????}else{
????????????println!("奇數(shù):{}",n)
????????}
????????n+=1;
????}
}
2.8、loop{} 和 while(true){}
從語法上理解,loop{} 和 while(true){} 這兩種是沒有任何區(qū)別的。 但相比于其他很多語言,Rust 語言要做更多的靜態(tài)分析,loop 和 while true 語句在運行時沒有任何區(qū)別,他們主要會影響編譯器內(nèi)部的靜態(tài)分析結(jié)果。 比如:
let?x;
loop{
????x?=?1;
????break;
}
println!("{}",x);
上面語句在Rust中完全合理,因為編譯器可以通過流程分析推理出x=1,必然在println!之前執(zhí)行過,所以打印x的值是完全合理的。 再比如對于while true 語句:
let?x;
while(true){
????x?=?1;
????break;
}
println!("{}",x);
報錯如下:

因為編譯器會覺得while 語句的執(zhí)行和條件表達式在運行階段的值有關(guān)(有可能while false,導(dǎo)致沒有運行 while 里面的語句,從而 x 沒有初始化),于是編譯器直接拋出一個未初始化異常。
2.9、for
Rust 中的for循環(huán)類似其他語言中的 for-each 循環(huán)。 for循環(huán)的主要用處是利用迭代器對包含同樣類型的多個元素的容器進行遍歷,如數(shù)組、鏈表、HashMap、HashSet等。
fn?for_test(){
????let?array?=?&[1,2,3,4,5];
????for?i?in?array?{
????????println!("The?Numer?is?{}",i);
????}
}
3、常見錯誤
3.1 連續(xù)賦值報錯
fn?f(a:bool,b:bool,c:bool)?->?bool{
????a?==?b?==?c
}
報錯如下:

3.2 漏掉 else 分支報錯
如果 else 分支省略掉了,編譯器會認為 else 分支的類型默認為(),但是 if 分支返回的是 i32 數(shù)據(jù)類型。
我們知道,使用 if-else 作為表達式,一定要注意 if 和 else 分支的類型必須一致,否則就不能構(gòu)成一個合法的表達式,會出現(xiàn)編譯錯誤。
fn?if_test()?->?i32{
????if?true?{
????????0
????}
????return?1;
}
編譯報錯:
