??團(tuán)隊(duì)博客: 汽車電子社區(qū)
一、概述
??Rust基本類型有如下幾種:
????1、數(shù)值類型: 有符號(hào)整數(shù) (i8, i16, i32, i64, isize)、 無(wú)符號(hào)整數(shù) (u8, u16, u32, u64, usize) 、浮點(diǎn)數(shù) (f32, f64)、以及有理數(shù)、復(fù)數(shù)。
????2、字符串:字符串字面量和字符串切片 &str。
????3、布爾類型: true和false。
????4、字符類型: 表示單個(gè) Unicode 字符,存儲(chǔ)為 4 個(gè)字節(jié)。
????5、單元類型: 即 () ,其唯一的值也是 ()。
二、數(shù)值類型
2.1、整數(shù)類型
??整數(shù)是沒(méi)有小數(shù)部分的數(shù)字。之前使用過(guò)的 i32 類型,表示有符號(hào)的 32 位整數(shù)( i 是英文單詞 integer 的首字母,與之相反的是 u,代表無(wú)符號(hào) unsigned 類型)。下表顯示了 Rust 中的內(nèi)置的整數(shù)類型:??isize 和 usize 類型取決于程序運(yùn)行的計(jì)算機(jī) CPU 類型: 若 CPU 是 32 位的,則這兩個(gè)類型是 32 位的,同理,若 CPU 是 64 位,那么它們則是 64 位。
??整形字面量可以用下表的形式書(shū)寫(xiě):??整型溢出:
??假設(shè)有一個(gè) u8 ,它可以存放從 0 到 255 的值。那么當(dāng)你將其修改為范圍之外的值,比如 256,則會(huì)發(fā)生整型溢出。關(guān)于這一行為 Rust 有一些有趣的規(guī)則:當(dāng)在 debug 模式編譯時(shí),Rust 會(huì)檢查整型溢出,若存在這些問(wèn)題,則使程序在編譯時(shí) panic(崩潰,Rust 使用這個(gè)術(shù)語(yǔ)來(lái)表明程序因錯(cuò)誤而退出)。
??在當(dāng)使用 --release 參數(shù)進(jìn)行 release 模式構(gòu)建時(shí),Rust 不檢測(cè)溢出。相反,當(dāng)檢測(cè)到整型溢出時(shí),Rust 會(huì)按照補(bǔ)碼循環(huán)溢出(two’s complement wrapping)的規(guī)則處理。簡(jiǎn)而言之,大于該類型最大值的數(shù)值會(huì)被補(bǔ)碼轉(zhuǎn)換成該類型能夠支持的對(duì)應(yīng)數(shù)字的最小值。比如在 u8 的情況下,256 變成 0,257 變成 1,依此類推。程序不會(huì) panic,但是該變量的值可能不是你期望的值。依賴這種默認(rèn)行為的代碼都應(yīng)該被認(rèn)為是錯(cuò)誤的代碼。
要顯式處理可能的溢出,可以使用標(biāo)準(zhǔn)庫(kù)針對(duì)原始數(shù)字類型提供的這些方法:
????1、使用 wrapping_* 方法在所有模式下都按照補(bǔ)碼循環(huán)溢出規(guī)則處理,例如 wrapping_add。
????2、如果使用 checked_* 方法時(shí)發(fā)生溢出,則返回None值。
????3、使用 overflowing_* 方法返回該值和一個(gè)指示是否存在溢出的布爾值。
????4、使用 saturating_* 方法使值達(dá)到最小值或最大值。
2.2、浮點(diǎn)類型
??浮點(diǎn)類型數(shù)字 是帶有小數(shù)點(diǎn)的數(shù)字,在 Rust 中浮點(diǎn)類型數(shù)字也有兩種基本類型: f32 和 f64,分別為 32 位和 64 位大小。默認(rèn)浮點(diǎn)類型是 f64,在現(xiàn)代的 CPU 中它的速度與 f32 幾乎相同,但精度更高。
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
??浮點(diǎn)數(shù)陷阱:
??浮點(diǎn)數(shù)由于底層格式的特殊性,導(dǎo)致了如果在使用浮點(diǎn)數(shù)時(shí)不夠謹(jǐn)慎,就可能造成危險(xiǎn),有兩個(gè)原因:
????1、浮點(diǎn)數(shù)往往是你想要數(shù)字的近似表達(dá) 浮點(diǎn)數(shù)類型是基于二進(jìn)制實(shí)現(xiàn)的,但是我們想要計(jì)算的數(shù)字往往是基于十進(jìn)制,例如 0.1 在二進(jìn)制上并不存在精確的表達(dá)形式,但是在十進(jìn)制上就存在。這種不匹配性導(dǎo)致一定的歧義性,更多的,雖然浮點(diǎn)數(shù)能代表真實(shí)的數(shù)值,但是由于底層格式問(wèn)題,它往往受限于定長(zhǎng)的浮點(diǎn)數(shù)精度,如果你想要表達(dá)完全精準(zhǔn)的真實(shí)數(shù)字,只有使用無(wú)限精度的浮點(diǎn)數(shù)才行。
????2、浮點(diǎn)數(shù)在某些特性上是反直覺(jué)的 例如大家都會(huì)覺(jué)得浮點(diǎn)數(shù)可以進(jìn)行比較,對(duì)吧?是的,它們確實(shí)可以使用 >,>= 等進(jìn)行比較,但是在某些場(chǎng)景下,這種直覺(jué)上的比較特性反而會(huì)害了你。因?yàn)?f32 , f64 上的比較運(yùn)算實(shí)現(xiàn)的是 std::cmp::PartialEq 特征(類似其他語(yǔ)言的接口),但是并沒(méi)有實(shí)現(xiàn) std::cmp::Eq 特征,但是后者在其它數(shù)值類型上都有定義,說(shuō)了這么多,可能大家還是云里霧里,用一個(gè)例子來(lái)舉例:
??Rust 的 HashMap 數(shù)據(jù)結(jié)構(gòu),是一個(gè) KV 類型的 Hash Map 實(shí)現(xiàn),它對(duì)于 K 沒(méi)有特定類型的限制,但是要求能用作 K 的類型必須實(shí)現(xiàn)了 std::cmp::Eq 特征,因此這意味著你無(wú)法使用浮點(diǎn)數(shù)作為 HashMap 的 Key,來(lái)存儲(chǔ)鍵值對(duì),但是作為對(duì)比,Rust 的整數(shù)類型、字符串類型、布爾類型都實(shí)現(xiàn)了該特征,因此可以作為 HashMap 的 Key。
??為了避免上面說(shuō)的兩個(gè)陷阱,你需要遵守以下準(zhǔn)則:
????1、避免在浮點(diǎn)數(shù)上測(cè)試相等性。
????2、當(dāng)結(jié)果在數(shù)學(xué)上可能存在未定義時(shí),需要格外的小心。
NaN
??對(duì)于數(shù)學(xué)上未定義的結(jié)果,例如對(duì)負(fù)數(shù)取平方根 -42.1.sqrt() ,會(huì)產(chǎn)生一個(gè)特殊的結(jié)果:Rust 的浮點(diǎn)數(shù)類型使用 NaN (not a number)來(lái)處理這些情況。
??所有跟 NaN 交互的操作,都會(huì)返回一個(gè) NaN,而且 NaN 不能用來(lái)比較,下面的代碼會(huì)崩潰:
fn main() {
let x = (-42.0_f32).sqrt();
assert_eq!(x, x);
}
??出于防御性編程的考慮,可以使用 is_nan() 等方法,可以用來(lái)判斷一個(gè)數(shù)值是否是 NaN :
fn main() {
let x = (-42.0_f32).sqrt();
if x.is_nan() {
println!("未定義的數(shù)學(xué)行為")
}
}
2.3、數(shù)字運(yùn)算
??Rust 支持所有數(shù)字類型的基本數(shù)學(xué)運(yùn)算:加法、減法、乘法、除法和取模運(yùn)算。下面代碼各使用一條 let 語(yǔ)句來(lái)說(shuō)明相應(yīng)運(yùn)算的用法:
fn main() {
// 加法
let sum = 5 + 10;
// 減法
let difference = 95.5 - 4.3;
// 乘法
let product = 4 * 30;
// 除法
let quotient = 56.7 / 32.2;
// 求余
let remainder = 43 % 5;
}
fn main() {
// 編譯器會(huì)進(jìn)行自動(dòng)推導(dǎo),給予twenty i32的類型
let twenty = 20;
// 類型標(biāo)注
let twenty_one: i32 = 21;
// 通過(guò)類型后綴的方式進(jìn)行類型標(biāo)注:22是i32類型
let twenty_two = 22i32;
// 只有同樣類型,才能運(yùn)算
let addition = twenty + twenty_one + twenty_two;
println!("{} + {} + {} = {}", twenty, twenty_one, twenty_two, addition);
// 對(duì)于較長(zhǎng)的數(shù)字,可以用_進(jìn)行分割,提升可讀性
let one_million: i64 = 1_000_000;
println!("{}", one_million.pow(2));
// 定義一個(gè)f32數(shù)組,其中42.0會(huì)自動(dòng)被推導(dǎo)為f32類型
let forty_twos = [
42.0,
42f32,
42.0_f32,
];
// 打印數(shù)組中第一個(gè)值,并控制小數(shù)位為2位
println!("{:.2}", forty_twos[0]);
}
2.4、位運(yùn)算
??Rust的運(yùn)算基本上和其他語(yǔ)言一樣。
fn main() {
// 二進(jìn)制為00000010
let a:i32 = 2;
// 二進(jìn)制為00000011
let b:i32 = 3;
println!("(a & b) value is {}", a & b);
println!("(a | b) value is {}", a | b);
println!("(a ^ b) value is {}", a ^ b);
println!("(!b) value is {} ", !b);
println!("(a << b) value is {}", a << b);
println!("(a >> b) value is {}", a >> b);
let mut a = a;
// 注意這些計(jì)算符除了!之外都可以加上=進(jìn)行賦值 (因?yàn)?=要用來(lái)判斷不等于)
a <<= b;
println!("(a << b) value is {}", a);
}
2.5、序列(Range)
??Rust 提供了一個(gè)非常簡(jiǎn)潔的方式,用來(lái)生成連續(xù)的數(shù)值,例如 1…5,生成從 1 到 4 的連續(xù)數(shù)字,不包含 5 ;1…=5,生成從 1 到 5 的連續(xù)數(shù)字,包含 5,它的用途很簡(jiǎn)單,常常用于循環(huán)中:
for i in 1..=5 {
println!("{}",i);
}
??序列只允許用于數(shù)字或字符類型,原因是:它們可以連續(xù),同時(shí)編譯器在編譯期可以檢查該序列是否為空,字符和數(shù)字值是 Rust 中僅有的可以用于判斷是否為空的類型。如下是一個(gè)使用字符類型序列的例子:
for i in 'a'..='z' {
println!("{}",i);
}
2.6、有理數(shù)和復(fù)數(shù)
??Rust 的標(biāo)準(zhǔn)庫(kù)相比其它語(yǔ)言,準(zhǔn)入門(mén)檻較高,因此有理數(shù)和復(fù)數(shù)并未包含在標(biāo)準(zhǔn)庫(kù)中:
????1、有理數(shù)和復(fù)數(shù)。
????2、任意大小的整數(shù)和任意精度的浮點(diǎn)數(shù)。
????3、固定精度的十進(jìn)制小數(shù),常用于貨幣相關(guān)的場(chǎng)景。
??好在社區(qū)已經(jīng)開(kāi)發(fā)出高質(zhì)量的 Rust 數(shù)值庫(kù):num。
use num::complex::Complex;
fn main() {
let a = Complex { re: 2.1, im: -1.2 };
let b = Complex::new(11.1, 22.2);
let result = a + b;
println!("{} + {}i", result.re, result.im)
}
三、字符、布爾、單元類型
3.1、字符類型
fn main() {
let c = 'z';
let z = '?';
let g = '國(guó)';
let heart_eyed_cat = '??';
}
??Rust 的字符不僅僅是 ASCII,所有的 Unicode 值都可以作為 Rust 字符,包括單個(gè)的中文、日文、韓文、emoji 表情符號(hào)等等,都是合法的字符類型。Unicode 值的范圍從 U+0000 ~ U+D7FF 和 U+E000 ~ U+10FFFF。不過(guò)“字符”并不是 Unicode 中的一個(gè)概念,所以人在直覺(jué)上對(duì)“字符”的理解和 Rust 的字符概念并不一致。
??由于 Unicode 都是 4 個(gè)字節(jié)編碼,因此字符類型也是占用 4 個(gè)字節(jié):
fn main() {
let x = '中';
println!("字符'中'占用了{(lán)}字節(jié)的內(nèi)存大小",std::mem::size_of_val(&x));
}
Rust 的字符只能用 ‘’ 來(lái)表示, “” 是留給字符串的
3.2、布爾類型(bool)
??Rust 中的布爾類型有兩個(gè)可能的值:true 和 false,布爾值占用內(nèi)存的大小為 1 個(gè)字節(jié):文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-809214.html
fn main() {
let t = true;
let f: bool = false; // 使用類型標(biāo)注,顯式指定f的類型
if f {
println!("這是段毫無(wú)意義的代碼");
}
}
3.3、單元類型
??單元類型就是 () ,對(duì),你沒(méi)看錯(cuò),就是 () ,唯一的值也是 () ,一些讀者讀到這里可能就不愿意了,你也太敷衍了吧,管這叫類型?
??只能說(shuō),再不起眼的東西,都有其用途,在目前為止的學(xué)習(xí)過(guò)程中,大家已經(jīng)看到過(guò)很多次 fn main() 函數(shù)的使用吧?那么這個(gè)函數(shù)返回什么呢?
??沒(méi)錯(cuò), main 函數(shù)就返回這個(gè)單元類型 (),你不能說(shuō) main 函數(shù)無(wú)返回值,因?yàn)闆](méi)有返回值的函數(shù)在 Rust 中是有單獨(dú)的定義的:發(fā)散函數(shù)( diverge function ),顧名思義,無(wú)法收斂的函數(shù)。
??例如常見(jiàn)的 println!() 的返回值也是單元類型 ()。
??再比如,你可以用 () 作為 map 的值,表示我們不關(guān)注具體的值,只關(guān)注 key。 這種用法和 Go 語(yǔ)言的 struct{} 類似,可以作為一個(gè)值用來(lái)占位,但是完全不占用任何內(nèi)存。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-809214.html
到了這里,關(guān)于深入理解Rust基本類型的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!