Rust 數(shù)據(jù)類型詳解
一、標(biāo)量類型(Scalar Types)
標(biāo)量類型代表一個(gè)單獨(dú)的值。Rust 中有四大基本標(biāo)量類型:整數(shù)(integer)、浮點(diǎn)數(shù)(floating-point number)、布爾(boolean)和字符(character)。這幾種類型在大多數(shù)編程語(yǔ)言中都很常見。
1. 整數(shù)類型(Integer Types)
整數(shù)(integer)是沒(méi)有小數(shù)部分的數(shù)字。在之前的猜數(shù)字游戲教程里,我們用到了 u32
。這個(gè)類型聲明表示該值是一個(gè)無(wú)符號(hào)(unsigned)32 位整數(shù)(如果是有符號(hào)類型,會(huì)以 i
開頭,例如 i32
)。
下表展示了 Rust 中所有內(nèi)置的整數(shù)類型,每個(gè)類型要么是有符號(hào)(signed),要么是無(wú)符號(hào)(unsigned),并且有明確的位數(shù)大小。
長(zhǎng)度 | 有符號(hào) | 無(wú)符號(hào) |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
- 有符號(hào)(signed)表示數(shù)值可能為正也可能為負(fù),所以存儲(chǔ)時(shí)需要符號(hào)位;
- 無(wú)符號(hào)(unsigned)則只表示非負(fù)數(shù)(0 或正數(shù)),不需要符號(hào)位。
對(duì)于有符號(hào)整數(shù),如果類型是 i8
,它可以存儲(chǔ)從 -128 到 127 的數(shù)值;若是 i16
,則范圍會(huì)相應(yīng)擴(kuò)大,以此類推。無(wú)符號(hào)類型則從 0 起算。例如 u8
能表示 0 到 255。
isize
和 usize
根據(jù)系統(tǒng)架構(gòu)的不同而變化:在 64 位架構(gòu)上是 64 位,在 32 位架構(gòu)上是 32 位。這些類型常用于根據(jù)系統(tǒng)架構(gòu)進(jìn)行索引或內(nèi)存大小計(jì)算等場(chǎng)景。
1.1 整數(shù)字面量
在 Rust 中可以使用多種形式來(lái)表達(dá)整數(shù)字面量(literal),如下表所示:
數(shù)字字面量形式 | 示例 |
---|---|
十進(jìn)制 | 98_222 |
十六進(jìn)制 | 0xff |
八進(jìn)制 | 0o77 |
二進(jìn)制 | 0b1111_0000 |
字節(jié)(僅限 u8 ) | b'A' |
注意:
- 可以在數(shù)字中使用下劃線
_
作為分隔符來(lái)提高可讀性,例如1_000
與1000
等價(jià)。 - 如果需要指定類型,可以在數(shù)字后面加上類型后綴,比如
57u8
。
通常如果不確定該用什么整數(shù)類型,Rust 默認(rèn)使用 i32
。若需要根據(jù)系統(tǒng)架構(gòu)進(jìn)行索引等場(chǎng)景時(shí),才考慮使用 isize
或 usize
。
1.2 整數(shù)溢出(Integer Overflow)
假設(shè)我們有一個(gè) u8
類型的變量,它能表示的數(shù)值范圍是 [0, 255]
。如果嘗試將其賦值為 256,就會(huì)發(fā)生整數(shù)溢出(integer overflow),導(dǎo)致以下兩種行為之一:
- 調(diào)試(debug)模式編譯:Rust 會(huì)執(zhí)行溢出檢查,一旦發(fā)現(xiàn)溢出,就會(huì)在運(yùn)行時(shí) panic(程序崩潰并退出)。
- 發(fā)布(release)模式編譯:Rust 不做溢出檢查,而是進(jìn)行二補(bǔ)碼環(huán)繞(two’s complement wrapping)。換言之,超出最大可表示值時(shí)會(huì)“環(huán)繞”回最小值。例如,對(duì)于
u8
類型,256 會(huì)變成 0,257 會(huì)變成 1,等等。不會(huì)出現(xiàn) panic,但是結(jié)果往往與期望不符。
在實(shí)際開發(fā)中,不應(yīng)依賴整數(shù)溢出的環(huán)繞行為,這被認(rèn)為是錯(cuò)誤的做法。若需要顯式處理溢出,可以使用標(biāo)準(zhǔn)庫(kù)里為整數(shù)提供的以下方法族:
wrapping_*
:如wrapping_add
,始終進(jìn)行環(huán)繞運(yùn)算;checked_*
:如checked_add
,若溢出則返回None
;overflowing_*
:如overflowing_add
,返回一個(gè)元組(結(jié)果, bool)
,其中bool
指示是否發(fā)生溢出;saturating_*
:如saturating_add
,在溢出時(shí)結(jié)果會(huì)自動(dòng)“飽和”到對(duì)應(yīng)類型的最小或最大值。
2. 浮點(diǎn)數(shù)類型(Floating-Point Types)
Rust 提供了兩種原生的浮點(diǎn)數(shù)類型:f32
(32 位)和 f64
(64 位)。默認(rèn)使用 f64
,因?yàn)樵诂F(xiàn)代 CPU 上,f64
與 f32
速度幾乎相當(dāng),但精度更高。所有浮點(diǎn)類型都是有符號(hào)數(shù)。
fn main() { let x = 2.0; // f64 let y: f32 = 3.0; // f32 println!("x = {}, y = {}", x, y); }
Rust 的浮點(diǎn)數(shù)遵循 IEEE-754 標(biāo)準(zhǔn)。
3. 數(shù)值運(yùn)算(Numeric Operations)
Rust 支持常見的數(shù)值運(yùn)算:加法、減法、乘法、除法和取余。需要注意的是,整數(shù)除法會(huì)向零方向取整(截?cái)嘈?shù)部分)。示例:
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; println!("sum = {}", sum); println!("difference = {}", difference); println!("product = {}", product); println!("quotient = {}", quotient); println!("remainder = {}", remainder); }
如果需要查看 Rust 提供的所有運(yùn)算符,可以參考 附錄 B。
4. 布爾類型(Boolean Type)
布爾類型(bool
)只有兩個(gè)可能的值:true
和 false
。它所占的大小是 1 個(gè)字節(jié)。例如:
fn main() { let t = true; let f: bool = false; println!("t = {}, f = {}", t, f); }
布爾常常用于條件判斷(如 if
表達(dá)式),后面會(huì)在“控制流”一節(jié)詳述。
5. 字符類型(Character Type)
Rust 的 char
類型是最基礎(chǔ)的字母類型,用單引號(hào)包裹,支持 Unicode Scalar Value。這意味著它可以表示除 ASCII 之外更多的字符,比如帶重音的拉丁字符、中文、日文、韓文、emoji、零寬空格等。例如:
fn main() { let c = 'z'; let z = '?'; let heart_eyed_cat = '??'; println!("{}, {}, {}", c, z, heart_eyed_cat); }
Rust 的 char
類型占 4 個(gè)字節(jié),對(duì)應(yīng) Unicode Scalar Value 范圍:U+0000
~ U+D7FF
和 U+E000
~ U+10FFFF
。需要注意的是,Unicode 的“字符”概念可能與人們直覺中的“字符”不完全一致。詳情可參考第 8 章關(guān)于字符串的討論。
二、復(fù)合類型(Compound Types)
復(fù)合類型可以將多個(gè)值組合成一個(gè)類型。Rust 提供了兩種原生的復(fù)合類型:元組(tuple)和數(shù)組(array)。
1. 元組類型(Tuple Type)
元組(tuple)可以將多個(gè)類型各異的值組合到一個(gè)復(fù)合類型中,長(zhǎng)度固定,不可增長(zhǎng)或縮短。使用小括號(hào) ()
包含并用逗號(hào)分隔不同的值。例如:
fn main() { let tup: (i32, f64, u8) = (500, 6.4, 1); println!("tup = {:?}", tup); }
1.1 解構(gòu)(Destructuring)元組
要獲取元組中的單獨(dú)值,可以使用模式匹配(pattern matching)進(jìn)行解構(gòu):
fn main() { let tup = (500, 6.4, 1); let (x, y, z) = tup; println!("y = {}", y); }
執(zhí)行后,y
的值就是 6.4
。這里 tup
被“拆解”成了 x
, y
, z
三個(gè)變量的過(guò)程,稱為解構(gòu)。
1.2 使用索引訪問(wèn)元組
也可以直接用點(diǎn)號(hào)加索引來(lái)訪問(wèn)元組的指定元素:
fn main() { let x: (i32, f64, u8) = (500, 6.4, 1); let five_hundred = x.0; let six_point_four = x.1; let one = x.2; println!("{}, {}, {}", five_hundred, six_point_four, one); }
需要注意,索引從 0 開始。
1.3 單元類型(Unit Type)
如果元組不包含任何元素,則被稱為單元元組(unit)。它寫作 ()
,表示一種空值或空的返回類型。若一個(gè)表達(dá)式?jīng)]有返回任何其他值,默認(rèn)會(huì)返回單元元組。
2. 數(shù)組類型(Array Type)
數(shù)組(array)也是一種把多個(gè)值組合在一起的方式,但它與元組有兩個(gè)主要區(qū)別:
- 數(shù)組中所有元素類型相同;
- 數(shù)組長(zhǎng)度固定,一旦聲明,長(zhǎng)度就無(wú)法改變。
例如:
fn main() { let a = [1, 2, 3, 4, 5]; println!("{:?}", a); }
數(shù)組通常存儲(chǔ)在棧上(stack)而不是堆上(heap),這在 第 4 章 會(huì)詳細(xì)解釋。若需要一個(gè)可伸縮的序列,則使用標(biāo)準(zhǔn)庫(kù)提供的 向量(vector,Vec<T>
)。如果你需要一個(gè)長(zhǎng)度固定的序列,數(shù)組就非常合適。比如月份名稱:
let months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
2.1 數(shù)組的類型注解
聲明數(shù)組類型時(shí),需要在方括號(hào)里寫元素類型、分號(hào)、元素個(gè)數(shù):
let a: [i32; 5] = [1, 2, 3, 4, 5];
這里 i32
是每個(gè)元素的類型,5
表示數(shù)組長(zhǎng)度。
2.2 初始化為相同元素
如果想讓數(shù)組的所有元素都相同,可以使用如下語(yǔ)法:
let a = [3; 5]; // 等價(jià)于 let a = [3, 3, 3, 3, 3];
2.3 訪問(wèn)數(shù)組元素
可以使用索引來(lái)訪問(wèn)數(shù)組元素:
fn main() { let a = [1, 2, 3, 4, 5]; let first = a[0]; let second = a[1]; println!("first = {}, second = {}", first, second); }
2.4 越界訪問(wèn)與運(yùn)行時(shí)錯(cuò)誤
如果索引超出了數(shù)組的長(zhǎng)度,Rust 會(huì)在運(yùn)行時(shí)檢查到錯(cuò)誤并 panic:
fn main() { let a = [1, 2, 3, 4, 5]; println!("請(qǐng)輸入一個(gè)數(shù)組索引。"); let mut index = String::new(); std::io::stdin() .read_line(&mut index) .expect("讀取失敗"); let index: usize = index .trim() .parse() .expect("輸入的索引不是數(shù)字"); let element = a[index]; println!("你選擇的元素是:{}", element); }
如果你輸入了超出 [0..4]
范圍的索引,比如 10,就會(huì)引發(fā) panic,顯示類似:
thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:19:19
程序因此退出并不會(huì)執(zhí)行后續(xù)的 println!
。這是 Rust 保證內(nèi)存安全的體現(xiàn):許多低級(jí)語(yǔ)言在越界索引時(shí)可能會(huì)訪問(wèn)非法內(nèi)存地址,引發(fā)不可預(yù)料的后果,而 Rust 直接在運(yùn)行時(shí)檢測(cè)并退出以保證安全。
小結(jié)
在本篇文章中,我們介紹了 Rust 最常用的兩種數(shù)據(jù)類型子集:標(biāo)量類型和復(fù)合類型。標(biāo)量類型包括整數(shù)、浮點(diǎn)數(shù)、布爾和字符,它們各自有不同的表示和范圍;復(fù)合類型包括元組和數(shù)組,可以用于將多個(gè)值組合到一個(gè)類型中,并且在長(zhǎng)度是否可變和類型一致性方面有所區(qū)別。
- 標(biāo)量類型:
- 整數(shù):如
i32
,u32
,i8
,u8
等,不同字長(zhǎng)和有符號(hào)/無(wú)符號(hào)選擇; - 浮點(diǎn)數(shù):
f32
和f64
,默認(rèn)使用f64
; - 布爾:
bool
,僅有true
和false
; - 字符:
char
,占 4 字節(jié),可表示 Unicode Scalar Value。
- 整數(shù):如
- 復(fù)合類型:
- 元組:可含多種類型,長(zhǎng)度固定;可用解構(gòu)或索引方式訪問(wèn);
- 數(shù)組:同類型元素的集合,長(zhǎng)度固定,存儲(chǔ)于棧上。
對(duì)于新手而言,遇到無(wú)法自動(dòng)推斷類型的情形時(shí),需要加上類型注解,尤其是在使用 parse
或其他需要指明具體數(shù)值類型的場(chǎng)景下。隨著實(shí)踐的深入,Rust 提供的多種安全檢查機(jī)制(如整數(shù)溢出檢查、數(shù)組越界檢查等)會(huì)給予你更多信心和安全感,同時(shí)也需要你熟悉這些機(jī)制以寫出高效且安全的代碼。
在后續(xù)章節(jié)中,我們將會(huì)不斷深入 Rust 的特性,包括所有權(quán)、引用與切片、集合類型(向量、字符串、哈希映射)以及錯(cuò)誤處理等,希望你能繼續(xù)保持對(duì) Rust 的探索與學(xué)習(xí)。
參考與致謝
- The Rust Programming Language - By Steve Klabnik and Carol Nichols, CC BY 4.0
- 本文部分內(nèi)容基于其翻譯和改寫,如需了解更多細(xì)節(jié),請(qǐng)閱讀官方文檔。
到此這篇關(guān)于Rust 數(shù)據(jù)類型詳解的文章就介紹到這了,更多相關(guān)Rust 數(shù)據(jù)類型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Rust錯(cuò)誤處理之`foo(...)?`的用法與錯(cuò)誤類型轉(zhuǎn)換小結(jié)
foo(...)?語(yǔ)法糖為Rust的錯(cuò)誤處理提供了極大的便利,通過(guò)結(jié)合map_err方法和From?trait的實(shí)現(xiàn),你可以輕松地處理不同類型的錯(cuò)誤,并保持代碼的簡(jiǎn)潔性和可讀性,這篇文章主要介紹了Rust錯(cuò)誤處理:`foo(...)?`的用法與錯(cuò)誤類型轉(zhuǎn)換,需要的朋友可以參考下2024-05-05淺談Rust?+=?運(yùn)算符與?MIR?應(yīng)用
這篇文章主要介紹了Rust?+=?運(yùn)算符與?MIR?應(yīng)用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-01-01