Rust從入門到精通05-語句和表達式
1、語句和表達式
語句和表達式是 Rust 語言實現邏輯控制的基本單元。
在 Rust 程序里面,語句(Statement)是執行一些操作但不返回的指令,表達式(Expressions)計算并產生一個值。
表達式可以是語句的一部分,反過來,語句也可以是表達式的一部分。
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);
}
{},也是一個表達式,表達式的結果是最后一行代碼,x + 1后面沒有分號,表示的是表達式,如果在表達式后面加上“;”,則表示語句,語句沒有返回值,則上面代碼會報錯。
1.3 總結
①、一個表達式總會產生一個值,因此它必然有類型。
②、語句不產生值,它的類型永遠是 ();
③、如果把一個表達式加上分號,那么它就變成了一個語句;
④、如果把一個語句放到一個語句塊中包起來,那么它就可以當成一個表達式使用。
Rust is primarily an expression language
翻譯過來:Rust 基本上就是一個表達式語言。
Rust 除了 let / static / const / fn 等少數語句外,Rust 絕大多數代碼都是表達式(expression)。
所以 if / while / for / loop 都會返回一個值,函數最后一個表達式就是函數的返回值,這和函數式編程語言一致。
語句就是計算結果為()的特殊表達式。Rust 編譯器,在解析代碼的時候,如果碰到分號,就會繼續往后執行。如果遇到語句,就執行語句;如果遇到表達式,則會對表達式求值;如果分號后面什么都沒有,就補上()。
2、算術表達式
2.1、算術運算符:+ - * / %
分別是加、減、乘、除、取余。
//加、減、乘、除、取余
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 禁止連續比較;
fn compare_test(a:bool,b:bool,c:bool) -> bool{
a==b==c
}
編譯報錯:

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

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

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

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

Rust 不支持連續的比較操作符進行多個值的比較。
3.2 漏掉 else 分支報錯
如果 else 分支省略掉了,編譯器會認為 else 分支的類型默認為(),但是 if 分支返回的是 i32 數據類型。
我們知道,使用 if-else 作為表達式,一定要注意 if 和 else 分支的類型必須一致,否則就不能構成一個合法的表達式,會出現編譯錯誤。
fn if_test() -> i32{
if true {
0
}
return 1;
}
編譯報錯:

浙公網安備 33010602011771號