【內容特點】
✯快速上手:專為 Python 開發者打造,用熟悉思維無縫接軌 Rust
✩解鎖高效能:掌握所有權與生命週期,根除記憶體錯誤並突破 GIL
✯PyO3 實戰:從零開始教你撰寫 Rust 擴充套件,解決 Python 運算瓶頸
✩AI 落地應用:駕馭 Candle 與 Burn 框架,實現輕量化推論與模型移植
✯工程化思維:涵蓋模組化設計、自動化測試到效能分析的完整實踐
【本書獻給不願在效能與開發效率間妥協的你】
✯資料科學家:受夠了 Pandas 在大數據下的龜速,想尋找更高效的運算替
代方案。
✩資料工程師:需要建構高吞吐量、低延遲且穩健可靠的 ETL 管線,徹底告
別執行期錯誤,讓資料流動不再阻塞。
✯ MLOps 工程師:致力於模型生產環境部署,追求在有限算力下達到極致的
推論速度。
✩進階 Python 開發者:不滿足於語法糖,想深入理解底層運作與並行程式設
計,大幅擴張技術守備範圍。
作者簡介:
顏志穎
現任外商科技公司資料工程師,專精於大規模資料處理與 MLOps 架構設計。
曾獲 iThome 鐵人賽 AI & Data 組佳作,熱衷於透過文字梳理技術脈絡。
長期沉浸於 Python 生態系,近年積極探索 Rust 在資料工程領域的實務應用,並樂於將這些「雙刀流」的實戰經驗轉化為文字,與社群共同成長。
工作之餘,是個相信吸貓能提升程式碼品質的快樂鏟屎官。
作者序
前言
歡迎來到《從 Pythonista 到 Rustacean:資料從業者的第一本 Rust 指南》!
我是一個在資料科學領域工作多年的工程師。我的職業生涯始於Python,至今它仍然是我日常工作的主力語言。
和許多Pythonista 一樣,我曾深受效能瓶頸與記憶體壓力的困擾。大約兩年前,我為了尋找突破點而開始接觸Rust。
起初,我只是驚艷於它的執行速度;但真正觸動我的,是它在不犧牲效能的前提下,透過所有權系統提供的「記憶體安全保證」。
當我意識到編譯器能在執行前就幫我攔截掉那些在Python 中最棘手的None錯誤、資料競爭(Data Race) 或記憶體洩漏時,我體會到了一種前所未有的「安心感」。
我開始在工作中將Rust 整合進Python 工作流程。無論是將關鍵的資料處理瓶頸改用Rust 重寫,或是建構高效能的模型推論服務,Rust 都確實地解決了許多過去棘手的問題。
這份「原來程式可以寫得又快又安全」的感動,就是我撰寫這本書的初衷。
我深信Rust 與Python 的結合是資料科學的未來。這本書便是我分享這份經驗的成果,希望能幫助更多和我有過相同困擾的Pythonista,找到一條新的、通往高效能與高穩定性的路徑。
本書宗旨
首先,必須澄清一點:這本書不是要您拋棄 Python。
Python 在資料科學領域的地位是不可動搖的,其豐富的生態系統、簡潔的語法、以及龐大的社群支援,都是無可替代的優勢。我自己也是Python 的忠實使用者,並且深信它仍會是資料科學的主要語言。
那為什麼要學Rust ?因為Rust 能成為Python 最好的夥伴。
當Python 遇到效能瓶頸時,Rust 可以接手;當您需要建構高並行的資料管線時,Rust 能提供安全保證;當您想要部署輕量級的模型服務時,Rust 能提供接近C 的效能,卻不用擔心記憶體錯誤。
簡單來說,這本書要傳達的是如何在正確的時機,選擇正確的工具。
市面上不乏優秀的 Rust 入門書,但本書的定位有些許不同。
這並非一本鉅細靡遺的Rust 語法大全,而是專為Pythonista 量身打造的實戰指南,其獨特之處在於:
1.從 Pythonista 的熟悉場景出發
2.目標導向的兩階段結構
Part I:Rust 的攀登之路 ( 第 1-8 章 )。
Part II:實戰應用! ( 第 9-12 章 )。
3.特有的「雙視角」標記系統
🐍 Pythonista 視角、🦀 Rustacean 思維
4.銜接更廣闊的 Rust 生態
準備好了嗎?
如果您已經迫不及待,那就讓我們翻到第一章,開始您的 Rust 之旅吧。
學習一門新的程式語言,本質上是在學習一種新的思考方式。
Rust 的某些概念( 尤其是所有權系統) 初期可能會帶來挑戰,這很正常。
但當您跨過這個門檻,理解了其設計背後的取捨,便會體會到它在安全與效能之間取得的巧妙平衡。
請保持耐心,專注於理解每個概念背後的「為什麼」。
讓我們開始吧。
顏志穎
前言
歡迎來到《從 Pythonista 到 Rustacean:資料從業者的第一本 Rust 指南》!
我是一個在資料科學領域工作多年的工程師。我的職業生涯始於Python,至今它仍然是我日常工作的主力語言。
和許多Pythonista 一樣,我曾深受效能瓶頸與記憶體壓力的困擾。大約兩年前,我為了尋找突破點而開始接觸Rust。
起初,我只是驚艷於它的執行速度;但真正觸動我的,是它在不犧牲效能的前提下,透過所有權系統提供的「記憶體安全保證」。
當我意識到編譯器能在執行前就幫我攔截掉那些在Python 中最棘手的None錯誤、資料競爭(Data Race) 或記憶...
目錄
▌Part I Rust 的攀登之路
►第1 章 建立新思維:Rust 的基本功與工具鏈
1.1 踏入Rust 世界:為何它值得Pythonista 注目?
1.2 安裝Rust 與設定開發環境
1.2.1安裝rustup
1.2.2驗證安裝
1.2.3更新Rust
1.2.4開發環境建議
1.3 Pythonista 的第一行Rust:Hello, Performance!
1.3.1建立專案資料夾與檔案
1.3.2編譯與執行
1.4 核心工具Cargo
1.4.1使用Cargo 建立新專案
1.4.2建構與執行 Cargo 專案
1.4.3Cargo 的常用指令
1.5 告別動態型別:認識變數與原始型別
1.5.1資料的綁定:變數、常數與可變性
1.5.2萬物的基礎:原始型別 (Primitive Types)
1.5.3數值的計算:基礎運算
1.6 組織程式碼:函式 (Functions) 與表達式
1.6.1函式簽章 (Function Signature)
1.6.2函式本體:陳述式 vs. 表達式
1.6.3萬物皆表達式 (Almost)
1.7 揭秘 !:函式的近親,巨集 (Macros)
1.7.1為什麼Rust 需要巨集?
1.7.2常用的內建巨集
1.7.3println! 的格式化功能
1.8 做出決策:if、else 與 match
1.8.1if、else if 與 else
1.8.2更強大的分支:match
1.9 重複的藝術:loop、while 與 for
1.9.1loop:無限迴圈
1.9.2while:條件迴圈
1.9.3for:走訪集合
巢狀迴圈與標籤 (Loop Labels)
1.10超越原始型別:三大常用集合 (Collections)
1.10.1 向量 (Vector)
1.10.2 字串 (String)
1.10.3 雜湊映射 (HashMap)
1.11專業風範:程式碼風格與文件化
1.11.1 註解
1.11.2 文件註解
1.11.3 模組與 Crate 文件
1.11.4 命名規範 (Naming Conventions)
1.12第一章的登山口:整備行囊與心態
►第2 章 Rust 風格的物件導向:Struct、Enum 與 Trait
2.1 結構體 (Struct):定義資料的藍圖
2.1.1經典結構體:我們的第一個自訂型別
2.1.2建立實例的便利語法
2.1.3結構體的其他形式
2.2 Impl ( 實作區塊):為資料賦予行為
2.2.1方法 (Methods):&self 的初登場
2.2.2關聯函式 (Associated Functions):Rust 的「 建構子」
2.3 列舉 (Enum):定義「多選一」的狀態
2.3.1從簡單列舉開始
2.3.2攜帶資料的變體:Enum 的真正力量
2.3.3match 窮舉:絕不遺漏任何情況
2.4 Option:Rust 的空值處理方案
2.4.1None 的問題,Option 的解法
2.4.2if let:match 的語法糖
2.5 Trait ( 特徵):定義共通的「能力」
2.5.1什麼是 Trait ?
2.5.2實作 Trait:賦予型別新能力
2.5.3使用 Trait 實現多型:泛型 (Generics)
2.5.4#[derive]:讓編譯器為我們工作
2.5.5常見的標準庫 Trait:From 與 Into
2.6 第二章的路線圖:辨識地形與規劃路徑
►第3 章 無 GC 的記憶體安全:所有權系統
3.1 記憶體小學堂
3.1.1基礎概念:記憶體的組織方式
3.1.2中階概念:記憶體的座標系統
3.1.3進階概念:記憶體的雙核心管理方式
3.1.4Stack 的誕生:解決記憶體管理的兩大挑戰
3.1.5Heap 的崛起:突破作用域與編譯期的大小限制
3.1.6所有權問題的浮現
3.2 所有權:Rust 記憶體管理的核心原則
3.2.1所有權的轉移:移動 (Move) vs. 複製 (Copy)
3.2.2所有權的訪問:借用 (&) 與參考 (Reference)
3.2.3解參考 (*):讀取參考背後的值
3.3 駕馭所有權:常見模式與實戰場景
3.3.1函式與資料的互動模式
3.3.2結構體與方法的設計模式
3.3.3錯誤診斷室:學會與編譯器對話
3.3.4所有權問題的思維框架
3.4 所有權試煉
試煉 3-1:報告的歸檔
試煉 3-2:狀態訊息的顯示
試煉 3-3:使用者的暱稱
3.5 第三章的陡峭岩壁:攀越所有權的考驗
►第4 章 優雅的資料處理:閉包與迭代器
4.1 什麼是閉包 (Closures) ?— 捕捉環境的匿名函式
4.1.1閉包的語法:從函式到閉包
4.1.2捕捉環境:閉包的核心威力
4.2 閉包如何捕捉環境:所有權的三種模式
4.2.1自動推論:不可變借用、可變借用與取得所有權
4.2.2move 關鍵字:強迫閉包取得所有權
4.3 什麼是迭代器 (Iterator) ?處理序列的「惰性」方法
4.3.1迭代器的「惰性」
4.3.2迭代器的三種模式:.iter(), .iter_mut(), .into_iter()
4.4 Iterator Trait:迭代器的「契約」
4.4.1核心方法:.next()
4.4.2消耗配接器 (Consuming Adaptors)
4.4.3迭代配接器 (Iterator Adaptors)
4.5 組合應用:Option 也能用函數式風格
4.5.1心智模型:將 Option 視為「長度 0 或 1」的集合
4.5.2常用組合器 (Combinators)
4.6 第四章的高速索道:串起流暢的資料管線
►第5 章 穩健的程式碼:Result 與 Panic
5.1 兩類錯誤:不可復原 vs. 可復原
5.1.1不可復原的錯誤:panic!
5.1.2可復原的錯誤:Result
5.2 panic!:當一切都已無可挽回
5.2.1拆解 (Unwind) vs. 中止 (Abort)
5.2.2追蹤 panic! 的根源:Backtrace
5.3 Result:明確處理「可能」的失敗
5.3.1Result 的本質:一個列舉
5.3.2處理 Result 的基本功:match
5.4 告別巢狀match:Result 的組合器
5.4.1使用 .unwrap_or_else 簡化 match
5.4.2快速原型開發:.unwrap() 與 .expect()
5.5 錯誤傳播 (Propagating):? 運算子
5.5.1傳統的錯誤傳播 ( 手動 match 與 return)
5.5.2現代的錯誤傳播:? 的魔力
5.5.3讓 main 函式回傳 Result
5.6 建立自己的錯誤型別
5.6.1建構子 (Constructor) 最佳實踐
5.6.2使用 enum 窮舉錯誤
5.6.3讓 enum 成為「真正」的錯誤
5.6.4終極捷徑:thiserror & anyhow Crate
5.7 第五章的風險管理:應對濃霧與突發坍方
►第6 章 擴展程式規模:模組化與測試
6.1 程式碼的「三層架構」:Packages, Crates, 與 Modules
6.1.1Package ( 套件):Cargo 的專案單位
6.1.2Crate:編譯的最小單位
6.1.3Module ( 模組):Crate 內部的組織單位
6.2 定義模組:mod 關鍵字與檔案系統
6.2.1內嵌模組:最直接的封裝
6.2.2拆分到檔案 (External File Modules)
6.3 控制可見性:pub 關鍵字與私有性
6.3.1預設私有
6.3.2pub 關鍵字:打開對外的那扇窗
6.3.3pub struct vs. pub enum:一個微妙的陷阱
6.3.4pub(crate):內部的「公開」
6.4 將項目引入作用域:use 關鍵字
6.4.1建立捷徑
6.4.2絕對路徑 vs. 相對路徑
6.4.3路徑管理:as 與 pub use
6.5 撰寫與組織測試
6.5.1測試的組織:內部實作 vs. 公開 API
6.5.2撰寫基本測試:#[test] 與驗證
6.5.3測試特殊情況:panic 與 Result
6.6 執行測試:cargo test 的選項
6.6.1執行特定測試
6.6.2控制測試執行
6.6.3忽略測試:#[ignore]
6.6.4cargo-nextest:更強大的測試執行器
6.7 第六章的前進營地:建立營區與設立檢查點
►第7 章 參考的有效期限:生命週期
7.1 為何需要生命週期?一切的起點:迷途參考
7.1.1一個無法編譯的程式:迷途參考的誕生
7.1.2拆解問題:作用域 (Scope) vs. 生命週期 (Lifetime)
7.2 泛型生命週期:當編譯器需要我們幫忙
7.2.1函式簽章:連結輸入與輸出的生命週期
7.2.2在資料結構中保存參考
7.2.3impl 區塊:為帶有生命週期的型別實作方法
7.3 喘口氣:生命週期省略規則(Lifetime Elision Rules)
7.4 特殊生命週期:'static
7.5 集大成:泛型、Trait 與生命週期
7.6 第七章的補給線:精算參考的安全期限
►第8 章 無懼的並行:執行緒、共享與同步
8.1 建立執行緒:thread::spawn
8.1.1thread::spawn 與 JoinHandle
8.1.2move 關鍵字:執行緒的所有權
8.2 執行緒通訊 (1):訊息傳遞 (Message Passing)
8.2.1mpsc 通道
8.2.2crossbeam-channel 與 MPMC 通道
8.3 智慧指標:為共享狀態做準備
8.3.1Box:單一所有權的 Heap 指標
8.3.2Rc:單一執行緒的多重所有權
8.3.3內部可變性:Cell 與 Copy 型別
8.3.4內部可變性:RefCell 與執行時借用
8.3.5經典組合:Rc>
8.3.6Arc:執行緒安全的多重所有權
8.4 執行緒通訊 (2):共享狀態 Mutex
8.4.1Mutex ( 互斥鎖)
8.4.2經典組合:Arc>
8.5 Rust 的終極保證:Send 與 Sync
8.5.1Send Trait:允許「所有權」跨執行緒轉移
8.5.2Sync Trait:允許「參考」跨執行緒共享
8.6 第八章的同步攻頂:從單人攀登到團隊協作
▌Part II 實戰應用!從 Python 擴充到 AI框架的完整旅程
►第9 章 PyO3:打造高效能的 Python 擴充套件
9.1 動機剖析:Python 為何需要 Rust 的力量?
9.1.1優異的編譯器與開發工具
9.1.2透過程序式巨集,弭平語言隔閡
9.1.3為沒有 GIL 的未來做好準備
9.2 環境設置:打造現代化的 PyO3 開發流程
9.2.1準備兩端的語言環境
9.2.2安裝建置工具 maturin
9.2.3建立 PyO3 專案
9.2.4第一次接觸:手動編譯與測試
9.2.5建立自動化測試流程
9.2.6深入探索:專案結構與核心設定檔
9.3 思維轉換:從 Python 物件到 Rust 型別
9.4 定義 Python 的入口:打造可 import 的模組
9.4.1基礎作法:以函式作為模組入口
9.4.2組織巢狀結構:子模組 (Submodule)
9.4.3更簡潔的選擇:用 mod 區塊宣告模組
9.5 打造工具:將 Rust 函式化為 Python 函式
9.5.1微調 Python 介面:#[pyo3] 屬性
9.5.2打造靈活的參數介面
9.5.3從Python 到 Rust:FromPyObject 特徵
9.5.4全域直譯器鎖 (GIL) 與安全的物件操作
9.5.5從 Rust 到 Python:IntoPyObject 特徵
9.5.6PyO3 的智慧指標體系:Py、Bound 與 Borrowed
9.5.7錯誤處理:當 Result 遇上 Exception
9.5.8核心觀念回顧
9.6 塑造物件:將 Rust 自訂型別化為 Python 類別
9.6.1第一步:用 #[pyclass] 勾勒藍圖輪廓
9.6.2千變萬化的 Enum:從狀態標籤到複合容器
9.6.3安全通關:進入 Python 世界的三個前提
9.6.4第二步:用 #[pymethods] 加裝操作功能
9.6.5物件的誕生:定義建構子
9.6.6開放內部資料:欄位的存取與修改
9.6.7工具箱與工廠:無需實例也能呼叫的方法
9.6.8跨越語言的繼承:讓 Rust 結構體也能開枝散葉
9.6.9行為的覆寫:在子類別中與父類別互動
9.6.10 #[pyclass] 旅程小結
9.7 跨越 GIL 的限制:Rust 的並行處理與 Free-threaded Python
9.7.1並行處理的兩種途徑:處理程序與執行緒
9.7.2Python 的現狀:在 GIL 下的權衡取捨
9.7.3打造 Rust 並行引擎:釋放多核心的潛能
9.7.4釋放 GIL 的安全前提
9.7.5精準的 GIL 管理:最小化鎖定時間
9.7.6在 Rust 執行緒間共享 Python 物件
9.7.7擁抱 Free-threaded Python 的未來
9.8 從 GIL 到無懼並行:為何 Python 更需要 Rust ?
►第10 章 Hugging Face Candle:點亮輕量化推論的極速火花
10.1 返璞歸真:從 Tensor 開始的 MNIST 訓練生活
10.1.1 打好地基:專案初始化與模組規劃
10.1.2 從雲端到記憶體:建構 MnistDataset
10.1.3 手刻線性層:理解 Candle 的參數管理哲學
10.1.4 建立漸進式重構工作台
10.1.5 使用 candle_nn::loss::cross_entropy 重構:從手動計算到最佳踐
10.1.6 使用 candle_nn::{Linear, Module} 重構:從手刻結構到慣用模式
10.1.7 使用 candle_nn::optim 重構:從手動更新到自動化迭代
10.1.8 整合與升級:使用 Batcher 打造現代化訓練迴圈
10.1.9 實戰演練:打造 LeNet-5 卷積神經網路
10.1.10 啟用硬體加速:釋放 GPU 的力量
10.1.11 打造流暢的資料管線:apply 鏈式呼叫
10.1.12 模型的保存與載入:延續訓練成果
10.1.13 打完收工:從手刻到框架的修煉之路
10.2 站在巨人的肩膀上:移植 PyTorch 模型
10.2.1 攤開巨人的藍圖:從 DistilBERT 開始
10.2.2 搭建施工鷹架:專案結構與模組規劃
10.2.3 萬丈高樓平地起:實作基礎元件庫 nn.rs
10.2.4 按圖施工:對應 transformers 原始碼
10.2.5 訂定施工規格:實作模型設定檔 config.rs
10.2.6 破土動工:實作輸入嵌入層 embeddings.rs
10.2.7 賦予專注力:實作多頭自注意力機制 attention.rs
10.2.8 打造標準樓層:實作單層 Transformer layer.rs
10.2.9 堆疊樓層成塔:實作 Transformer 編碼器 encoder.rs
10.2.10 從思緒到語言:實作 MLM 預測頭部 head.rs
10.2.11 竣工收尾:組裝完整 DistilBERT 模型 distilbert.rs
10.2.12 驗收成果:在 main.rs 中執行推論
10.3 燭光遍照:從單點模型到完整生態系
►第11 章 Burn:燃起 AI 研究與工程的熊熊烈焰
11.1 研製第一艘火箭:用 MNIST 演練從設計到升空的完整流程
11.1.1 發射台整備:專案初始化與架構藍圖
11.1.2 認識箭體材質:Burn 張量的特性與操作
11.1.3 打造燃料輸送帶:定義 Dataset 與 Dataloader
11.1.4 組裝箭體與酬載:定義 Burn 的模型結構 (Module 與 Config)
11.1.5 倒數計時與點火:實作訓練迴圈與 Learner
11.1.6 第二節推進:理解 Backend 並切換至 GPU 加速
11.1.7 封存航行日誌:模型的儲存
11.1.8 來自天際的應答:載入模型並驗證推論成果
11.1.9 章節總結:第一艘火箭的誕生
11.2 停靠太空站:匯入跨框架模型 (ONNX & Safetensors)
11.2.1 選擇你的對接口:架構生成 vs. 權重裝填
11.2.2 航線 A:ONNX - 自動化模型生成
11.2.3 航線 B:Safetensors - 手動對接與權重裝填
11.2.4 排除對接故障:處理框架不匹配問題
11.2.5 總結:擴展你的 Burn 艦隊
11.3 從火花到烈焰:Burn 與 Candle 的設計哲學,航向 AI 的無垠宇宙
►第12 章 效能分析工具箱:讓 Rust 跑得更快
12.1 效能的度量衡:使用 cargo bench 建立基準
12.1.1 建立我們的第一個 Benchmark
12.2 找出效能熱點:兩大視覺化利器
12.2.1 火焰圖 (Flamegraph) 的基本概念
12.2.2 如何閱讀火焰圖?
12.2.3 利器一號:經典 cargo-flamegraph
12.2.4 效能分析的陷阱:採樣到的是誰?
12.2.5 利器二號:現代 samply
12.2.6 解讀 samply 的多重視圖
12.3 記憶體:隱形的效能殺手
12.3.1 記憶體配置的成本 (Allocation Cost)
12.3.2 跨平台的 Rust Heap 分析器:Dhat
12.3.3 Dhat 之外:平台原生分析工具
12.3.4 超越演算法:CPU 快取的影響
12.4 效能思維:從量測到效能調校的完整循環
►附錄A :打造高效 Rust 開發環境(VS Code 篇)
A.1 必備工具鏈
rust-analyzer
CodeLLDB
A.2 輔助工具
Even Better TOML
ErrorLens
Dependi ( 前身為 Crates)
A.3 風格主題
Catppuccin
►附錄B :找回熟悉的開發節奏:設定Rust REPL 與Jupyter
B.1 終端機 REPL
B.1.1 evcxr_repl
B.1.2 IRust
B.2 Jupyter 整合
B.2.1 安裝 evcxr Jupyter Kernel
B.2.2 在 Jupyter 中使用 Rust
B.2.3 IRust Kernel
B.3 超越 REPL:Rustacean 的工作流
▌Part I Rust 的攀登之路
►第1 章 建立新思維:Rust 的基本功與工具鏈
1.1 踏入Rust 世界:為何它值得Pythonista 注目?
1.2 安裝Rust 與設定開發環境
1.2.1安裝rustup
1.2.2驗證安裝
1.2.3更新Rust
1.2.4開發環境建議
1.3 Pythonista 的第一行Rust:Hello, Performance!
1.3.1建立專案資料夾與檔案
1.3.2編譯與執行
1.4 核心工具Cargo
1.4.1使用Cargo 建立新專案
1.4.2建構與執行 Cargo 專案
1.4.3Cargo 的常用指令
1.5 告別動態型別:認識變數與原始型別
1.5.1資料的綁定:變數、常數與可變性
1.5.2萬物的基礎:原...
購物須知
退換貨說明:
會員均享有10天的商品猶豫期(含例假日)。若您欲辦理退換貨,請於取得該商品10日內寄回。
辦理退換貨時,請保持商品全新狀態與完整包裝(商品本身、贈品、贈票、附件、內外包裝、保證書、隨貨文件等)一併寄回。若退回商品無法回復原狀者,可能影響退換貨權利之行使或須負擔部分費用。
訂購本商品前請務必詳閱退換貨原則。