型別(數字詳解)
本集目標
認識 Rust 所有的數字型別,以及數字後綴的用法。
正文
上一集我們簡單認識了 i32 和 f64。今天來把 Rust 所有的數字型別都看一遍。
整數型別
Rust 的整數型別分成有號(可以是負數)和無號(只能是正數和零):
| 有號 | 無號 | 位元數 | 範圍(有號) |
|---|---|---|---|
i8 | u8 | 8 | -128 ~ 127 |
i16 | u16 | 16 | -32,768 ~ 32,767 |
i32 | u32 | 32 | 約 ±21 億 |
i64 | u64 | 64 | 超級大 |
i128 | u128 | 128 | 天文數字 |
isize | usize | 看系統 | 64 位元系統 = 64 位元 |
i= integer(整數),u= unsigned(無號)。- 數字代表用幾個位元來存——位元越多,能存的數字越大。
isize和usize的大小取決於你的系統是 32 位元還是 64 位元(現在幾乎都是 64 位元)。
日常用 i32 就夠了。 不確定的時候,用 i32。
浮點數型別
浮點數用來表示可以有小數部分的數值,在 Rust 裡有兩種:
| 型別 | 精確度 |
|---|---|
f32 | 單精度(約 7 位有效位數) |
f64 | 雙精度(約 15 位有效位數) |
日常用 f64 就夠了。 Rust 預設的浮點數就是 f64。
浮點數運算
第 5 集教算術運算的時候,我們都用整數。浮點數一樣可以用 + - * / %,但有一個重要的差別——浮點數除法可以得到小數部分:
fn main() {
let a = 10.0;
let b = 3.0;
println!("{}", a / b); // 3.3333333333333335
println!("{}", a % b); // 1
}
還記得第 5 集 10 / 3 的結果是 3(整數除法直接截斷)嗎?浮點數不會截斷,10.0 / 3.0 會得到 3.3333...。
另外注意 a % b 印出來的是 1 而不是 1.0。別誤會——它的型別還是 f64,只是 {} 在印浮點數時,小數部分是零就不會多印一個 .0。
不過浮點數有一個經典的坑——精確度問題:
fn main() {
println!("{}", 0.1 + 0.2); // 0.30000000000000004
}
0.1 + 0.2 不是 0.3!這不是 Rust 的 bug,而是幾乎所有程式語言都有的浮點數精確度限制。電腦用二進位存小數,有些十進位小數沒辦法精確表示。知道有這件事就好,不用太擔心。
Rust 怎麼推斷數字型別?
當你寫 let x = 5;,Rust 預設把它當成 i32。
當你寫 let y = 3.14;,Rust 預設把它當成 f64。
但 Rust 不只看數字本身,它也會根據你怎麼使用這個變數來推斷型別。有時候根據上下文,Rust 會推斷出 i32 以外的整數型別。這個之後遇到的時候會更清楚。
不過基本上來說,整數預設就是 i32、浮點數預設就是 f64。
數字後綴(literal suffix)
如果你想要指定型別,除了 let x: i64 = 5; 之外,還有一個更簡潔的寫法——直接在數字後面加型別名稱:
fn main() {
let a = 5i32; // i32
let b = 5u8; // u8
let c = 3.14f64; // f64
let d = 2.0f32; // f32
let e = 100000i64; // i64
println!("{} {} {} {} {}", a, b, c, d, e);
}
5i32 意思就是「5 這個數字,型別是 i32」。數字和型別之間不用空格,直接接在一起。
小提醒
不同型別的數字不能直接混著算:
fn main() {
let a: i32 = 5;
let b: i64 = 10;
println!("{}", a + b); // ❌ 編譯錯誤!i32 和 i64 不能直接相加
}
這是 Rust 的安全設計:Rust 一般不自動幫你轉換型別。
重點整理
- 整數分有號(
i8-i128)和無號(u8-u128),日常用i32就夠了。 isize和usize的大小取決於系統(64 位元上是 64 位元)。- 浮點數有
f32和f64,日常用f64(Rust 預設)。 - 數字後綴(如
5i32、3.14f64)可以直接指定型別。 - 浮點數除法可以得到小數部分,但有精確度問題(
0.1 + 0.2 ≠ 0.3)。 - Rust 一般不自動幫你轉換型別。