跳轉到

2.1 變數、型別與函式#

一個反直覺的預設:不可變#

Rust 最讓初學者意外的第一件事:變數預設不可變(immutable)。要能改,必須明確宣告 mut:

fn main() {
    let x = 5;
    // x = 6;              // ← 編譯錯誤!x 不可變

    let mut y = 5;
    y = 6;                 // ✓ 有 mut 才能改

    const MAX: u32 = 100;  // 常數:編譯期決定,型別必須寫明
}

工程意義:預設不可變,讓「這個值會不會被改」在程式碼上一眼可見。 需要可變性時,mut 是一個明確的承諾,review 時會被特別檢視。

基本型別#

fn main() {
    // 整數:i8/i16/i32/i64/i128/isize 與 u 開頭的無號版(u8/u32...)
    let a: i32 = -42;      // 預設整數型別是 i32
    let b: u8 = 255;

    // 浮點數
    let f: f64 = 3.14;     // 預設是 f64

    // 布林與字元
    let t: bool = true;
    let c: char = '中';    // char 是 4 bytes,支援 Unicode

    // 字串:兩種,初學者必分
    let s1: &str = "hello";           // 字串切片(字面值就是 &str)
    let s2: String = String::from("hello"); // 有所有權的字串(可增長)
}

常見困惑:&str 與 String 的區別——String 擁有資料(可修改、可增長),&str 是借用的一段文字(唯讀、不可增長)。函式參數若只是要讀文字,慣用 &str。

型別推導與轉換#

Rust 有強大的型別推導——大多數時候不用寫型別,只在必要時標註:

let x = 5;              // 編譯器推導為 i32
let y: f64 = 3.0;       // 需要明確指定時才寫

// Rust 不做隱式轉換,必須明確:
let n = 5;
let m: f64 = n as f64;  // 明確轉型
// let p: f64 = n;      // ← 編譯錯誤!i32 不會自動轉 f64

沒有隱式轉換是刻意的:型別之間的轉換必須明確寫出來,避免「悄悄縮小精度」之類的隱藏錯誤。

函式#

fn main() {
    let r = add(3, 4);
    println!("3 + 4 = {}", r);

    let s = greeting("小美");
    println!("{}", s);
}

// 參數必須標型別;回傳型別用 -> 標註
fn add(a: i32, b: i32) -> i32 {
    a + b               // ← 最後一行「沒有分號」就是回傳值
}

fn greeting(name: &str) -> String {
    format!("你好,{}", name)  // format! 產生 String
}

初學者最容易踩的坑:最後一行「有沒有分號」決定是不是回傳值。

fn add(a: i32, b: i32) -> i32 {
    a + b     // ✓ 回傳 a+b
}

fn add2(a: i32, b: i32) -> i32 {
    a + b;    // ← 編譯錯誤!分號讓它變成「敘述」,沒有回傳值
}

控制流#

fn main() {
    let n = 7;

    // if 是「運算式」,可以賦值(條件不用括號)
    let tag = if n % 2 == 0 { "偶數" } else { "奇數" };

    // 迴圈三種
    for i in 0..5 {           // 0,1,2,3,4(range,最常用)
        print!("{} ", i);
    }
    for i in 0..=5 {          // 含結尾:0..5
        print!("{} ", i);
    }

    let mut count = 0;
    while count < 3 {
        count += 1;
    }

    loop {                    // 無限迴圈,用 break 帶回傳值
        count += 1;
        if count > 10 { break count; }
    }
}

本章小結#

  • 變數預設不可變,mut 是明確的承諾
  • 基本型別:i32/u8/f64/bool/char;String 擁有資料,&str 是借用
  • 沒有隱式型別轉換,轉型要明確 as
  • 函式:參數標型別、-> 標回傳;最後一行沒有分號就是回傳值
  • if 和迴圈都是運算式,可以賦值

想一想#

  1. 「預設不可變」對程式可讀性與 review 有什麼幫助?
  2. String 和 &str 的差別是什麼?函式參數該用哪個?
  3. a + b 和 a + b; 的差別是什麼?這個設計的代價與好處各是什麼?