Rust 基本語法與變數 — 資料型態(整數、浮點數、布林值、字元)
簡介
在程式語言的世界裡,資料型態是所有變數與常數的根基。Rust 以安全與效能為設計核心,對型別的檢查相當嚴格,這讓開發者能在編譯期即捕捉許多潛在錯誤。了解整數、浮點數、布林值與字元的行為與限制,是寫出正確、可預測程式的第一步。
本單元將帶你一步步認識 Rust 常用的四大基礎型別,並透過實作範例說明它們在真實專案中的應用方式。即使你是剛接觸 Rust 的新手,只要跟著本文的步驟走,也能快速上手,為後續更進階的所有權與錯誤處理打下堅實基礎。
核心概念
1. 整數(Integer)
Rust 提供多種寬度與有號/無號的整數型別,常見的有 i8、i16、i32、i64、i128 以及對應的 u8、u16、u32、u64、u128。預設情況下,字面值會被推斷為 i32,除非你顯式指定。
1.1 基本宣告與型別推斷
fn main() {
// 型別推斷為 i32
let a = 42;
// 明確指定為 u8
let b: u8 = 255;
// i64 範例,使用後綴 `i64`
let c = 1_000_000i64;
println!("a = {}, b = {}, c = {}", a, b, c);
}
註解:_ 只是一個視覺上的分隔符,編譯器會忽略它,方便閱讀大數字。
1.2 溢位檢查(Overflow)
在 debug 模式下,Rust 會在執行階段檢查整數溢位;在 release 模式則會採用兩補數的包裹行為(wrap around)。若需要明確的包裹行為,可使用 wrapping_* 方法。
fn main() {
let max_u8: u8 = u8::MAX; // 255
// Debug 會 panic,Release 會 wrap
// let overflow = max_u8 + 1; // 直接加會在 debug 時 panic
// 使用 wrapping_add 強制包裹
let wrapped = max_u8.wrapping_add(1);
println!("wrapped = {}", wrapped); // 0
}
1.3 型別轉換(Casting)
Rust 不允許隱式轉換,必須使用 as 明確轉型。注意在轉型時可能會發生截斷或符號位變化。
fn main() {
let small: u8 = 200;
// 轉成 i16,保持數值
let larger = small as i16;
// 轉成 i8,會截斷高位
let truncated = small as i8; // 結果為 -56
println!("larger = {}, truncated = {}", larger, truncated);
}
2. 浮點數(Floating‑point)
Rust 內建兩種 IEEE‑754 標準的浮點型別:f32(單精度)與 f64(雙精度),預設為 f64。浮點數適合處理科學計算與圖形渲染等需要小數的情境。
2.1 基本使用
fn main() {
let x = 3.14; // 推斷為 f64
let y: f32 = 2.71828; // 明確指定為 f32
println!("x = {}, y = {}", x, y);
}
2.2 特殊值:NaN 與 Infinity
浮點運算可能產生 NaN(Not a Number) 或正負無限大。使用 is_nan()、is_infinite() 來檢測。
fn main() {
let nan = 0.0_f64 / 0.0;
let inf = 1.0_f64 / 0.0;
println!("nan is NaN? {}", nan.is_nan()); // true
println!("inf is infinite? {}", inf.is_infinite()); // true
}
2.3 精度比較
直接比較兩個浮點數是否相等往往不安全,建議使用容差(epsilon)判斷。
fn approx_eq(a: f64, b: f64, epsilon: f64) -> bool {
(a - b).abs() < epsilon
}
fn main() {
let a = 0.1 + 0.2;
let b = 0.3;
println!("a == b? {}", approx_eq(a, b, 1e-10));
}
3. 布林值(Boolean)
布林型別只有兩個可能值:true 與 false。它是控制流程(if、while)的核心。
3.1 基本範例
fn main() {
let is_rust_fun: bool = true;
let is_sunny = false; // 型別推斷
if is_rust_fun && !is_sunny {
println!("今天寫 Rust,天氣雖然不佳,但仍然很開心!");
}
}
3.2 與條件運算子結合
Rust 沒有傳統的三元運算子 (?:);可以使用 if 表達式直接回傳值。
fn main() {
let score = 85;
let grade = if score >= 60 { "合格" } else { "不合格" };
println!("成績判定:{}", grade);
}
4. 字元(Char)
Rust 的 char 代表 Unicode scalar value,占 4 個位元組,可直接處理中文、表情符號等多國語言文字。
4.1 單一字元宣告
fn main() {
let latin = 'R';
let chinese = '中';
let emoji = '🚀';
println!("{} {} {}", latin, chinese, emoji);
}
4.2 迭代字元與字串長度
String 與 &str 以 UTF‑8 編碼儲存,len() 回傳的是位元組長度;若要取得字元數,需要使用 .chars().count()。
fn main() {
let s = "Rust🚀語言";
println!("位元組長度: {}", s.len()); // 13
println!("字元數: {}", s.chars().count()); // 5
}
4.3 字元與位元組的轉換
使用 as u32 可取得字元的 Unicode 編碼點,反之則可透過 std::char::from_u32 建立字元。
fn main() {
let c = '🦀';
let code = c as u32;
println!("🦀 的 Unicode 編碼: U+{:X}", code);
let restored = std::char::from_u32(code).unwrap();
println!("還原後的字元: {}", restored);
}
常見陷阱與最佳實踐
| 陷阱 | 說明 | 建議的做法 |
|---|---|---|
| 隱式型別推斷 | 在大型程式中,過度依賴推斷會讓讀者不易判斷變數寬度,尤其是整數。 | 明確標註 重要變數的型別(如 u64、i128),避免未預期的截斷。 |
| 整數溢位 | Debug 模式會 panic,Release 會包裹,兩者行為不一致。 | 在可能會溢位的運算使用 checked_*、wrapping_* 或 saturating_* 系列方法,並自行處理 Option 結果。 |
| 浮點比較 | 直接 a == b 可能因精度誤差失敗。 |
使用 容差比較(epsilon)或 approx_eq 函式。 |
| 字元 vs 位元組 | String::len() 回傳位元組長度,易與字元數混淆。 |
需要字元數時,使用 s.chars().count();若只關心位元組大小,則直接 len()。 |
| 布林值的隱晦 | 把非布林值直接當條件使用會編譯錯誤(Rust 不允許隱式轉換)。 | 始終使用布林表達式,如 if x > 0 {},而非 if x {}。 |
最佳實踐小結
- 顯式型別:在公共 API 或跨平台程式碼中,盡量寫出完整型別。
- 錯誤處理:對可能失敗的型別轉換(如
from_u32)使用match或unwrap_or。 - 使用標準庫:
std::num::Wrapping、checked_*系列提供安全的算術操作,優先考慮。 - 文件化:在程式碼註解或
///文件中說明為何選擇特定寬度或精度,提升可維護性。
實際應用場景
| 場景 | 需要的型別 | 為何選擇 |
|---|---|---|
| 計算金融利息 | i64、f64 |
金額常以最小貨幣單位(如分)存於 i64,最後再轉為 f64 顯示小數點。 |
| 圖形渲染座標 | f32 |
大量座標計算,使用單精度可減少記憶體與運算成本,且精度足以滿足螢幕像素。 |
| 旗標與權限 | u8、u32 |
使用位元運算管理多個布林旗標,u32 能容納 32 個獨立權限。 |
| 文字處理(多語系) | char、String |
需要支援中文、日文、表情符號等 Unicode,char 能完整表示單一碼點。 |
| 感測器資料 | i16、u16 |
大多數硬體感測器回傳 16 位元有號或無號整數,直接對映到相同型別可避免轉換成本。 |
總結
本篇文章從 整數、浮點數、布林值、字元 四大基礎型別出發,說明了 Rust 如何透過嚴格的型別系統與豐富的標準庫方法,協助開發者寫出安全且效能佳的程式碼。掌握型別推斷與顯式宣告的平衡、了解溢位與精度比較的陷阱、善用 as 轉型與 checked_* 系列函式,都是在實務開發中不可或缺的技巧。
未來當你在撰寫更複雜的資料結構或與外部系統互動時,這些基礎型別的概念將成為你解決問題的根本工具。祝你在 Rust 的旅程中,寫出 安全、快速、易讀 的程式!