Rust語言教程(2) - 從熟悉的部分開始
雖然有默認不變性還有所有權的問題讓Rust一上來用起來有些不同,但是其實大部分語法特點還是我們所熟悉的蝴蜓。
我們沒必要上來就跟自己死磕呐萨,可以先從我們熟悉的部分開始學習税产。
一般我們寫代碼凭涂,使用的主要是數(shù)據(jù)類型田盈、控制結構和函數(shù)拍冠。我們就從這三部分開始尿这。
數(shù)據(jù)類型
與Go一樣,Rust的定義語句數(shù)據(jù)也是放在變量名后面的庆杜,不過還要加上一個冒號射众。
布爾類型
布爾類型是bool:
let b0 : bool = true;
因為Rust是有類型推斷的功能,所以很多時候可以不用指定類型晃财。
let b1 = true;
let b2 = !b1;
let b3 = 1 > 0;
println!("{} {} {}",b1,b2,b3);
如果使用CLion等IDE的話叨橱,就可以直接看到IDE提供的灰色的類型推斷的提示,非常方便:
字符類型 - 傳統(tǒng)與現(xiàn)代的結合
Rust的字符類型支持的是Unicode類型断盛,占用4個字節(jié)罗洗。同時,Rust也支持單字節(jié)ASCII值钢猛,這時用b開頭伙菜,類型值就是8位無符號類型u8。
我們來看例子:
let c1 :char = 'C';
let c2:u8 = b'C';
let c3 = '中';
println!("{} {} {}",c1,c2,c3);
同樣命迈,我們可以將字符組成字符串贩绕,我們來看例子:
let s1 = "Hello";
let s2 = b"World";
println!("{} {:?}",s1,s2);
輸出結果為:
Hello [87, 111, 114, 108, 100]
s1的真實類型是str類型,而s2是u8的數(shù)組壶愤。
let s1 :&str = "Hello";
let s2 :&[u8;5] = b"World";
整數(shù)類型: 后綴與下劃線齊飛
按照長度淑倾,Rust的整數(shù)類型支持8位,16位征椒,32位踊淳,64位,128位陕靠。根據(jù)有符號和無符號,分為有符號的i8,i16,i32,i64,i128和無符號的u8,u16,u32,u64,u128脱茉。
除此之外剪芥,也有根平臺相關的類型,有符號為isize類型琴许,無符號為usize類型税肪。
我們看下例子:
let i1 : i8 = -8;
let i2 : i16 = -16;
let i3 : i32 = -32;
let i4 : i64 = -64;
let i5 : i128 = -128;
let u1 : u8 = 8;
let u2 : u16 = 16;
let u3 : u32 = 32;
let u4 : u64 = 64;
let u5 : u128 = 128;
let p1 : isize = -1;
let p2 : usize = 1;
上面都是跟其它語言比較像,下面我們來看看Rust特色的后綴。這在C++中也有益兄,比如10l, 200L之類的锻梳。
在Rust中,我們直接用類型名做為后綴净捅,我們看個例子:
let i6 = -1i8;
let i7 = -2i16;
這樣放在一起可能不太容易區(qū)分疑枯,沒關系,Rust允許我們在數(shù)字上任意的加下劃線來提升可讀性蛔六,我們來看幾個例子:
let i08 = -3_i32;
let i09 = -4__i64;
let i10 = -5___i128;
下劃線并非只是用于數(shù)字和類型區(qū)分荆永,也可以加在數(shù)字中間,我們來看個例子:
let u6 = 1_000_000_u128;
println!("{}",u6);
默認的整數(shù)類型是i32国章,如果Rust無法推斷中整數(shù)的類型具钥,那么就默認為i32.
整數(shù)的進制
在Rust中,避免了077這樣對八進制的偏愛液兽,改為用0o來表示8進制整數(shù)骂删。16進制仍然是0xFF前綴,二進制用0b前綴四啰。
我們看例子:
let u07 = 0xFF_u32;
let u08 = 0o7777_u32;
let u09 = 0b01_10_00_u8;
println!("{} {} {}",u07,u08,u09);
輸出結果為:
255 4095 24
整數(shù)的溢出
在C語言中宁玫,整數(shù)的溢出也是一個常出現(xiàn)的問題。
對此拟逮,Rust在debug模式下撬统,在編譯時會檢查整數(shù)的溢出的問題:
let i_10 : i8 = 0x7f;
let i_11 : i8 = i_10 * 10i8;
println!("{}",i_11);
在編譯時,Rust就會報錯:
84 | let i_11 : i8 = i_10 * 10i8;
| ^^^^^^^^^^^ attempt to compute `i8::MAX * 10_i8`, which would overflow
懂程序分析的同學可能會想敦迄,在編譯時檢查不出來怎么辦恋追?好辦,我們在運行時進行檢查罚屋。
我們來個例子:
let mut i_20 : i8 = 0x20;
for i in 1..20{
i_20 = 0x20_i8 * i_20;
}
println!("{}",i_20);
在運行時仍然發(fā)現(xiàn)了溢出:
thread 'main' panicked at 'attempt to multiply with overflow', src/main.rs:91:16
stack backtrace:
0: rust_begin_unwind
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:483
1: core::panicking::panic_fmt
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:85
2: core::panicking::panic
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:50
3: tools::test
at ./src/main.rs:91
4: tools::main
at ./src/main.rs:34
5: core::ops::function::FnOnce::call_once
at /Users/lusinga/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
類型轉(zhuǎn)換
Rust語言是強類型的語言苦囱,不像C一樣有默認的類型轉(zhuǎn)換。如果進行跨類型計算需要進行類型轉(zhuǎn)換脾猛。
類型轉(zhuǎn)換使用“as 類型”的方法來寫撕彤,我們來看個例子:
let i_100 : i32 = (16i8 + 1) as i32;
i8計算之后還是i8,不能直接賦給i32類型猛拴,需要通過as i32來轉(zhuǎn)換類型羹铅。
如果計算的類型不同,編譯不報錯愉昆,在運行的時候也會被檢查出來职员。
我們看個例子:
let i_101 = 16i8 + 32i32;
會報下面的錯:
error[E0308]: mismatched types
--> src/main.rs:99:24
|
99 | let i_101 = 16i8 + 32i32;
| ^^^^^ expected `i8`, found `i32`
后面還有一個有趣的報錯,讓trait露了一個爪吁烁取:
error[E0277]: cannot add `i32` to `i8`
--> src/main.rs:99:22
|
99 | let i_101 = 16i8 + 32i32;
| ^ no implementation for `i8 + i32`
|
= help: the trait `Add<i32>` is not implemented for `i8`
浮點數(shù)
浮點數(shù)跟C語言差不多焊切,分為32位浮點數(shù)和64位浮點數(shù)扮授,就這兩種,分別是f32和f64专肪。默認為f64刹勃。
我們來看兩個例子:
let f_01 = 2.1;
let f_02 = 2e8;
f_01和f_02都是f64類型。
需要注意的是嚎尤,對于除0的處理荔仁,會引入兩個新的值:
- 對于非0除以0,得到的將是無窮大inf
- 而對于0除以0诺苹,將得到NaN咕晋,意思是并不是一個數(shù)
我們來看例子:
let f_03 = 0.0 / 0.0;
let f_04 = 1.0 / 0.0;
println!("{} {}",f_03,f_04);
輸出結果為:
NaN inf
NaN對應的本尊是std::f64::NAN,而inf是std::f64::INFINITY收奔,我們將其排列在一起:
let f_03 = 0.0 / 0.0;
let f_04 = 1.0 / 0.0;
let f_05 = std::f64::INFINITY;
let f_06 = std::f64::NAN;
println!("{} {} {} {}",f_03,f_04,f_05,f_06);
輸出結果為:
NaN inf inf NaN
32位和64位的無窮大都是無窮大掌呜,它們是相等的:
let f_10 = std::f32::INFINITY;
let f_11 = std::f64::INFINITY;
println!("{}",f_11==f_10 as f64);
輸出結果為:
true
但是要注意的是,兩個NAN是不相等的:
let f_12 = std::f64::NAN;
println!("{}",f_12==f_12);
結果為false.
流程控制
分支語句
Rust支持if-else表達式坪哄,用來處理分支质蕉。
if后面不必加括號,有點像Go翩肌,我們看個例子:
if n >= 100 {
println!("Grade A");
}else if n>= 60 {
println!("Pass");
}else{
println!("Fail");
}
可以寫成更像表達式一點的方式:
let grade = if n == 100{
"A"
}else if n>=60{
"Pass"
}else{
"Fail"
};
如果用作表達式的話模暗,if和else兩個分支返回的結果需要轉(zhuǎn)換成同一類型,畢竟Rust是這么強類型的語言念祭。
循環(huán)語句
Rust的循環(huán)分為三種:死循環(huán)loop兑宇,while循環(huán)和for循環(huán)。
loop最直接干脆粱坤,不需要while(true)
或者for(;;)
這種寫法隶糕,直接loop。如果需要退出循環(huán)就用break站玄,繼續(xù)下一輪循環(huán)就用continue枚驻。
我們來個簡單例子:
let mut num = 0;
let mut sum = 0;
loop{
if num > 10 {
break;
}else{
sum += num;
num += 1;
}
}
println!("sum={}",sum);
我們再將其翻譯成while循環(huán):
num = 0;
sum = 0;
while num <= 10 {
sum += num;
num += 1;
}
println!("sum={}", sum);
與if一樣,while后面也不強制要求括號株旷。
最后是for循環(huán)再登,它主要用于迭代器的遍歷:
sum = 0;
for i in 0..11 {
sum += i;
}
println!("sum={}", sum);
函數(shù)
最后說下函數(shù),Rust的函數(shù)使用fn關鍵字來定義晾剖。返回值的類型用->分隔而不是":"锉矢。
另外,Rust中不一定非要用return語句來返回值齿尽,表達式的值即可沈撞,我們看個例子:
fn fib2(n: i32) -> i64 {
if n <= 2 {
1i64
} else {
fib2(n - 1) + fib2(n - 2)
}
}
按傳統(tǒng)寫法也是可以的:
fn fib2(n: i32) -> i64 {
if n <= 2 {
return 1i64
} else {
return fib2(n - 1) + fib2(n - 2)
}
}
或者將return提到if表達式外面:
fn fib2(n: i32) -> i64 {
return if n <= 2 {
1i64
} else {
fib2(n - 1) + fib2(n - 2)
}
}
小結
在使用基本類型的情況下,Rust跟C語言和Go語言的基礎部分其實還是很類似的雕什,熟悉Javascript等語言的同學也不會覺得陌生缠俺。我們可以把原有的知識遷移過來,基本類型變量如果需要修改值的話就加個mut贷岸。