技術筆記 / Rust

Phase 1:型別系統與錯誤處理

目標:轉換思維 — 用 Rust 的方式思考資料結構與錯誤。

Rust 沒有繼承,沒有 null,沒有 exception,但更強大、更安全。


1. Struct(結構體)

1.1 命名結構體


// 定義資料結構(類似 Java 的 class,但只有資料,沒有行為)

struct User {

    username: String,

    email: String,

    age: u32,

    active: bool,

}



// 建立實例

let user = User {

    username: String::from("kirin"),

    email: String::from("[email protected]"),

    age: 25,

    active: true,

};



// 欄位更新語法(Field Update Syntax)

let user2 = User {

    email: String::from("[email protected]"),

    ..user  // 其他欄位從 user 複製

};

1.2 用 impl 加入行為


impl User {

    // 關聯函式(類似 static method)— 不接受 self

    fn new(username: &str, email: &str) -> Self {

        User {

            username: username.to_string(),

            email: email.to_string(),

            age: 0,

            active: true,

        }

    }



    // 方法(接受 &self = 不可變借用)

    fn display(&self) {

        println!("{} <{}>", self.username, self.email);

    }



    // 可變方法(接受 &mut self)

    fn deactivate(&mut self) {

        self.active = false;

    }

}

1.3 Tuple Struct


struct Color(u8, u8, u8);    // RGB

struct Point(f64, f64);



let red = Color(255, 0, 0);

let origin = Point(0.0, 0.0);



println!("紅色: ({}, {}, {})", red.0, red.1, red.2);


2. Enum(枚舉)— Rust 的超級武器

Rust 的 Enum 遠比 Java 的 Enum 強大,因為它的每個 variant 都可以攜帶不同型別的資料。


// 基本 Enum

enum Direction {

    North,

    South,

    East,

    West,

}



// 攜帶資料的 Enum(這才是精華)

enum Shape {

    Circle(f64),                    // 半徑

    Rectangle(f64, f64),            // 寬、高

    Triangle { base: f64, height: f64 },  // 具名欄位

}



impl Shape {

    fn area(&self) -> f64 {

        match self {

            Shape::Circle(r) => std::f64::consts::PI * r * r,

            Shape::Rectangle(w, h) => w * h,

            Shape::Triangle { base, height } => 0.5 * base * height,

        }

    }

}


3. Pattern Matching(模式比對)— Rust 的靈魂

3.1 基本 match


let num = 3;



match num {

    1 => println!("一"),

    2 | 3 => println!("二或三"),      // | 表示「或」

    4..=6 => println!("四到六"),      // 範圍

    _ => println!("其他"),            // _ 是萬用(必須存在,確保完整覆蓋)

}



// match 也是表達式,可以回傳值

let description = match num {

    1 => "one",

    2 => "two",

    3 => "three",

    _ => "many",

};

3.2 解構 Enum


let shape = Shape::Rectangle(4.0, 6.0);



match shape {

    Shape::Circle(r) => println!("圓形,半徑 {}", r),

    Shape::Rectangle(w, h) => println!("長方形 {}x{}", w, h),

    Shape::Triangle { base, height } => println!("三角形"),

}

3.3 if let — 只關心一個 variant


// 比 match 更簡潔,當你只關心一種情況時

let some_value = Some(42);



if let Some(x) = some_value {

    println!("有值: {}", x);

}

// 等價於:

match some_value {

    Some(x) => println!("有值: {}", x),

    None => {},

}


4. Option — 取代 null


// Option<T> 的定義(標準庫內建):

// enum Option<T> {

//     Some(T),

//     None,

// }



fn find_user(id: u32) -> Option<String> {

    if id == 1 {

        Some(String::from("Kirin"))

    } else {

        None  // 明確表示「找不到」,而不是回傳 null

    }

}



let result = find_user(1);



// 方式 1:match(最明確)

match result {

    Some(name) => println!("找到使用者: {}", name),

    None => println!("找不到"),

}



// 方式 2:unwrap_or(提供預設值)

let name = find_user(99).unwrap_or(String::from("匿名"));



// 方式 3:map(對 Some 的值做轉換)

let upper = find_user(1).map(|name| name.to_uppercase());



// 方式 4:? 運算子(在函式中傳播 None)— 詳見 Result 章節


5. Result — 取代 Exception


// Result<T, E> 的定義:

// enum Result<T, E> {

//     Ok(T),

//     Err(E),

// }



use std::num::ParseIntError;



fn parse_age(s: &str) -> Result<u32, ParseIntError> {

    let age: u32 = s.trim().parse()?;  // ? 運算子:成功取值,失敗提早回傳 Err

    Ok(age)

}



// 處理 Result

match parse_age("25") {

    Ok(age) => println!("年齡: {}", age),

    Err(e) => println!("解析失敗: {}", e),

}



// ? 運算子:自動 early return Err

fn process(input: &str) -> Result<String, ParseIntError> {

    let n = input.trim().parse::<i32>()?;  // 失敗就提早回傳 Err

    Ok(format!("數值的兩倍是 {}", n * 2))

}


練習題


cargo run -p phase1_types --example ex01_shapes

cargo run -p phase1_types --example ex02_card_game

cargo run -p phase1_types --example ex03_error_handling

cargo test -p phase1_types

與 Java/Python 對比

| 概念 | Rust | Java | Python |

|------|------|------|--------|

| 資料結構 | struct + impl | class | class |

| 繼承 | 不支援(用 Trait 組合) | extends | 繼承 |

| null | 無,用 Option<T> | null | None(可能拋 AttributeError) |

| 例外 | 無,用 Result<T,E> | throws Exception | raise Exception |

| 枚舉值 | 可攜帶任意資料 | 只有常數 | Enum 類似常數 |

在 GitHub 看原文