| name | rust-design-patterns |
| description | Rust 慣用設計模式技能。涵蓋 Builder Pattern(型別安全構建器)、 Newtype Pattern(型別封裝與 Deref)、Typestate Pattern(編譯期狀態機)、 RAII Guard Pattern(資源管理)、Interior Mutability(Cell/RefCell/Mutex)、 Strategy Pattern(trait objects vs enum dispatch)、 Command Pattern、Observer Pattern(回呼與事件系統)、 Extension Trait Pattern、Sealed Trait Pattern、From/Into 慣用轉換。 觸發關鍵詞:Rust design pattern, builder, newtype, typestate, RAII, interior mutability, strategy pattern, trait object, enum dispatch, sealed trait, extension trait, From Into, guard pattern
|
Rust 慣用設計模式
適用場景
- 設計新的 struct/API 時,需要選擇合適的建構方式(Builder / Typestate)
- 需要對原始型別加上語意約束或防止混用(Newtype)
- 管理需要確定釋放的資源(檔案、鎖、連線)→ RAII Guard
- 在不可變結構中仍需局部可變性 → Interior Mutability
- 需要執行時多態策略切換 → Strategy(trait object / enum dispatch)
- 限制 trait 只能在本 crate 實作 → Sealed Trait
- 為外部型別追加方法 → Extension Trait
- 事件驅動回呼架構 → Observer / Command Pattern
- 型別間慣用轉換 → From / Into / TryFrom
核心知識
模式索引表
| 模式 | 用途 | 複雜度 |
|---|
| Newtype | 為既有型別建立語意包裝,防止混用 | ★☆☆ |
| From/Into | 型別間慣用零成本轉換 | ★☆☆ |
| Builder (基礎) | 多欄位 struct 的鏈式建構 | ★★☆ |
| Typestate Builder | 編譯期強制必填欄位順序 | ★★★ |
| RAII Guard | 利用 Drop 自動釋放資源 | ★★☆ |
| Interior Mutability | 在 &self 下進行可變操作 | ★★☆ |
| Strategy (trait object) | 執行時動態切換行為 | ★★☆ |
| Strategy (enum dispatch) | 靜態分派、無堆積配置 | ★★☆ |
| Sealed Trait | 限制 trait 只能在本 crate 實作 | ★★☆ |
| Extension Trait | 為外部型別追加方法 | ★☆☆ |
| Observer / Callback | 事件訂閱與通知 | ★★★ |
| Command | 將操作封裝為物件,支援 undo | ★★☆ |
各模式詳解
1. Newtype Pattern
將原始型別包進單欄位 tuple struct,獲得:
- 型別安全:
UserId(u64) 與 OrderId(u64) 編譯期不可混用
- 封裝:可為 newtype 實作自訂方法與 trait
- 零成本:編譯後與原始型別完全相同的記憶體佈局
struct Meters(f64);
struct Seconds(f64);
impl std::ops::Deref for Meters {
type Target = f64;
fn deref(&self) -> &f64 { &self.0 }
}
搭配 From/Into:提供慣用的型別轉換,避免手動 .0 存取。
impl From<f64> for Meters {
fn from(v: f64) -> Self { Meters(v) }
}
2. Builder Pattern(基礎)
適用於有多個可選欄位的 struct:
struct Config {
host: String,
port: u16,
max_retries: u32,
}
struct ConfigBuilder {
host: String,
port: u16,
max_retries: u32,
}
impl ConfigBuilder {
fn new(host: impl Into<String>) -> Self { }
fn port(mut self, port: u16) -> Self { self.port = port; self }
fn max_retries(mut self, n: u32) -> Self { self.max_retries = n; self }
fn build(self) -> Config { }
}
也可使用 typed-builder crate 以 derive macro 自動生成。
3. Typestate Builder
利用泛型參數的零大小型別 (ZST) 在編譯期追蹤狀態:
struct NoHost;
struct HasHost;
struct RequestBuilder<H> {
host: Option<String>,
_state: std::marker::PhantomData<H>,
}
impl RequestBuilder<NoHost> {
fn host(self, h: impl Into<String>) -> RequestBuilder<HasHost> { }
}
impl RequestBuilder<HasHost> {
fn send(self) -> Response { }
}
優點:錯誤在編譯期捕獲,不需 runtime 檢查。
4. RAII Guard Pattern
Rust 的 Drop trait 保證離開作用域時自動執行清理:
struct TimerGuard { start: std::time::Instant, label: String }
impl Drop for TimerGuard {
fn drop(&mut self) {
println!("{}: {:?}", self.label, self.start.elapsed());
}
}
常見用途:MutexGuard、檔案鎖、計時器、交易回滾。
5. Interior Mutability
| 型別 | 執行緒安全 | 檢查時機 | 典型場景 |
|---|
Cell<T> | 否 | 編譯期(Copy) | 簡單計數器 |
RefCell<T> | 否 | 執行時借用 | 圖結構、快取 |
Mutex<T> | 是 | 執行時鎖 | 多執行緒共享 |
RwLock<T> | 是 | 讀寫鎖 | 讀多寫少 |
OnceCell/LazyLock | 是 | 僅初始化一次 | 全域單例 |
use std::cell::RefCell;
struct Cache {
data: RefCell<HashMap<String, String>>,
}
impl Cache {
fn get_or_insert(&self, key: &str) -> String {
let mut map = self.data.borrow_mut();
map.entry(key.to_owned())
.or_insert_with(|| expensive_compute(key))
.clone()
}
}
6. Strategy Pattern
Trait object 版本(動態分派,適合插件架構):
trait Compressor: Send + Sync {
fn compress(&self, data: &[u8]) -> Vec<u8>;
}
fn process(compressor: &dyn Compressor, data: &[u8]) -> Vec<u8> {
compressor.compress(data)
}
Enum dispatch 版本(無堆積配置,效能更佳):
enum Compressor { Gzip, Lz4, Zstd }
impl Compressor {
fn compress(&self, data: &[u8]) -> Vec<u8> {
match self {
Self::Gzip => { }
Self::Lz4 => { }
Self::Zstd => { }
}
}
}
選擇原則:變體固定 → enum;需外部擴展 → trait object。
7. Sealed Trait Pattern
防止下游 crate 實作你的 trait:
mod private { pub trait Sealed {} }
pub trait MyTrait: private::Sealed {
fn method(&self);
}
impl private::Sealed for MyStruct {}
impl MyTrait for MyStruct { fn method(&self) { } }
8. Extension Trait Pattern
為外部型別追加方法而不需要 Newtype:
pub trait StrExt {
fn is_blank(&self) -> bool;
}
impl StrExt for str {
fn is_blank(&self) -> bool {
self.trim().is_empty()
}
}
9. Observer / Callback Pattern
type Callback<T> = Box<dyn Fn(&T) + Send + 'static>;
struct EventBus<T> {
listeners: Vec<Callback<T>>,
}
impl<T> EventBus<T> {
fn subscribe(&mut self, cb: impl Fn(&T) + Send + 'static) {
self.listeners.push(Box::new(cb));
}
fn emit(&self, event: &T) {
for listener in &self.listeners {
listener(event);
}
}
}
10. Command Pattern
trait Command {
fn execute(&mut self);
fn undo(&mut self);
}
將操作封裝為實作 Command 的結構體,支援 undo/redo 堆疊。
程式碼範例
完整可編譯範例見 examples/ 目錄:
- basic.rs — Newtype + From/Into + Builder(基礎版)
- intermediate.rs — Typestate Builder + RAII Guard + Interior Mutability
- advanced.rs — Strategy (trait object + enum) + Sealed Trait + Extension Trait + Observer
常見錯誤對照表
| 錯誤訊息 | 原因 | 修復方式 |
|---|
the trait Sealed is not implemented for MyType | 嘗試在外部 crate 實作 Sealed Trait | 這是設計意圖;改用該 crate 提供的型別 |
already borrowed: BorrowMutError (runtime panic) | RefCell 同時存在 borrow() 與 borrow_mut() | 縮小借用範圍,或改用 Cell<T> / Mutex<T> |
cannot move out of self which is behind a mutable reference | Builder 方法用 &mut self 但嘗試消耗 self | 改用 self(owned)作為 builder 方法接收者 |
unused type parameter H | Typestate 泛型參數未被實際欄位使用 | 新增 PhantomData<H> 欄位 |
trait objects cannot have associated functions | trait 內含 fn new() -> Self 等方法,無法做 dyn Trait | 加上 where Self: Sized 或移至 companion function |
cannot return reference to temporary value | RAII guard 的 Deref 回傳了臨時值的參考 | 確保 guard 內部持有擁有權的資料,Deref 回傳其參考 |
the trait bound Send is not satisfied | 將 Rc<RefCell<T>> 用於多執行緒 | 改用 Arc<Mutex<T>> |
Cargo.toml 依賴模板
[dependencies]
derive_more = { version = "2.0", features = ["from", "deref", "display"] }
typed-builder = "0.20"
thiserror = "2"
once_cell = "1.20"
參考來源
- Rust Design Patterns Book — 社群維護的模式集
- The Rust Book — Ch.17 OOP Features — trait objects 與動態分派
- Rust API Guidelines — Type Safety — Newtype 與型別安全
- Cliffle — Typestate Pattern — Typestate 深入教學
- Rust Reference — Drop — RAII 與 Drop 語意
- derive_more 文件 — 自動 derive 工具
- typed-builder 文件 — 型別安全 Builder derive