<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Pyo3 on Tarragon</title><link>https://tarrragon.github.io/blog/tags/pyo3/</link><description>Recent content in Pyo3 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 21 Jan 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/pyo3/index.xml" rel="self" type="application/rss+xml"/><item><title>案例：PyO3 文字解析</title><link>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/pyo3-parser/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/pyo3-parser/</guid><description>&lt;p>本案例基於 &lt;code>.claude/lib/markdown_link_checker.py&lt;/code> 的實際程式碼，展示如何用 PyO3 和 Rust 實現高效能的文字解析器。&lt;/p>
&lt;h2 id="先備知識">先備知識&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/" data-link-title="模組六：用 Rust 擴展 Python" data-link-desc="學習使用 PyO3 和 Maturin 用 Rust 擴展 Python">模組五：用 Rust 擴展 Python&lt;/a>&lt;/li>
&lt;li>Rust 基礎語法&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/python-advanced/05-c-extensions/case-studies/cython-markdown/" data-link-title="案例：Cython 加速 Markdown 解析" data-link-desc="用 Cython 加速 Markdown 連結解析器，比較純 Python 與 Cython 的效能差異">5.1 Cython 加速&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="問題背景">問題背景&lt;/h2>
&lt;h3 id="現有設計">現有設計&lt;/h3>
&lt;p>&lt;code>markdown_link_checker.py&lt;/code> 使用純 Python 的正則表達式解析 Markdown 連結：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">re&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">MarkdownLinkChecker&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Markdown 連結檢查器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="c1"># Markdown 連結正則表達式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 匹配 [text](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/target) 格式，排除圖片 ![alt](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/src)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="n">INLINE_LINK_PATTERN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">compile&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s1">&amp;#39;(?&amp;lt;!!)\[([^\]]+)\]\(([^)]+)\)&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 引用式連結定義 [ref]: target&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> &lt;span class="n">REFERENCE_DEF_PATTERN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">compile&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s1">&amp;#39;^\s*\[([^\]]+)\]:\s*(.+)$&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MULTILINE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 引用式連結使用 [text][ref]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="n">REFERENCE_USE_PATTERN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">compile&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s1">&amp;#39;\[([^\]]+)\]\[([^\]]+)\]&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">parse_markdown_links&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Dict&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="s2"> 解析 Markdown 內容中的所有連結
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="s2"> Args:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="s2"> content: Markdown 內容
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="s2"> Returns:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="s2"> list[dict]: 連結列表，每個包含 text, target, line
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl"> &lt;span class="n">links&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl"> &lt;span class="n">lines&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 首先收集引用式連結定義&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl"> &lt;span class="n">reference_defs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="k">match&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">REFERENCE_DEF_PATTERN&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">finditer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl"> &lt;span class="n">ref_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">match&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lower&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl"> &lt;span class="n">ref_target&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">match&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl"> &lt;span class="n">reference_defs&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ref_name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ref_target&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">43&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">44&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 追蹤是否在程式碼區塊內&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">45&lt;/span>&lt;span class="cl"> &lt;span class="n">in_code_block&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">46&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">47&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 解析行內連結&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">48&lt;/span>&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">line_num&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">line&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">enumerate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lines&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">start&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">49&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 檢查程式碼區塊開始/結束&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">50&lt;/span>&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">startswith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;```&amp;#34;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">51&lt;/span>&lt;span class="cl"> &lt;span class="n">in_code_block&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">in_code_block&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">52&lt;/span>&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">53&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">54&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 跳過程式碼區塊內的連結&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">55&lt;/span>&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">in_code_block&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">56&lt;/span>&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">57&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">58&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 行內連結 [text](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/target)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">59&lt;/span>&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="k">match&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">INLINE_LINK_PATTERN&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">finditer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">line&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">60&lt;/span>&lt;span class="cl"> &lt;span class="n">links&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">61&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">match&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">62&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;target&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">match&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">63&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;line&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">line_num&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">64&lt;/span>&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">65&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">66&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 引用式連結 [text][ref]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">67&lt;/span>&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="k">match&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">REFERENCE_USE_PATTERN&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">finditer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">line&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">68&lt;/span>&lt;span class="cl"> &lt;span class="n">ref_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">match&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lower&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">69&lt;/span>&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">ref_name&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">reference_defs&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">70&lt;/span>&lt;span class="cl"> &lt;span class="n">links&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">71&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">match&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">72&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;target&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">reference_defs&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ref_name&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">73&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;line&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">line_num&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">74&lt;/span>&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">75&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">76&lt;/span>&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">links&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這段程式碼的核心瓶頸：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>正則表達式解析&lt;/strong>：Python 的 &lt;code>re&lt;/code> 模組效能有限&lt;/li>
&lt;li>&lt;strong>字串分割與迭代&lt;/strong>：大量的記憶體配置&lt;/li>
&lt;li>&lt;strong>字典操作&lt;/strong>：每個連結都建立新字典&lt;/li>
&lt;/ol>
&lt;h3 id="為什麼選擇-rust">為什麼選擇 Rust？&lt;/h3>
&lt;p>相比 Cython：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>面向&lt;/th>
 &lt;th>Cython&lt;/th>
 &lt;th>Rust (PyO3)&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>記憶體安全&lt;/td>
 &lt;td>依賴 GC&lt;/td>
 &lt;td>編譯時保證&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>正則表達式&lt;/td>
 &lt;td>仍用 Python re&lt;/td>
 &lt;td>原生 regex crate&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>錯誤處理&lt;/td>
 &lt;td>例外機制&lt;/td>
 &lt;td>Result 類型&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>多執行緒&lt;/td>
 &lt;td>受 GIL 限制&lt;/td>
 &lt;td>可完全繞過 GIL&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>生態系統&lt;/td>
 &lt;td>有限&lt;/td>
 &lt;td>豐富的 Cargo 生態&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="進階解決方案">進階解決方案&lt;/h2>
&lt;h3 id="設計目標">設計目標&lt;/h3>
&lt;ol>
&lt;li>用 Rust 重寫核心解析邏輯&lt;/li>
&lt;li>保持 Python API 相容&lt;/li>
&lt;li>實現顯著的效能提升&lt;/li>
&lt;/ol>
&lt;h3 id="實作步驟">實作步驟&lt;/h3>
&lt;h4 id="步驟-1建立-rust-專案結構">步驟 1：建立 Rust 專案結構&lt;/h4>
&lt;p>首先，使用 Maturin 建立新專案：&lt;/p></description><content:encoded><![CDATA[<p>本案例基於 <code>.claude/lib/markdown_link_checker.py</code> 的實際程式碼，展示如何用 PyO3 和 Rust 實現高效能的文字解析器。</p>
<h2 id="先備知識">先備知識</h2>
<ul>
<li><a href="/blog/python-advanced/06-rust-extensions/" data-link-title="模組六：用 Rust 擴展 Python" data-link-desc="學習使用 PyO3 和 Maturin 用 Rust 擴展 Python">模組五：用 Rust 擴展 Python</a></li>
<li>Rust 基礎語法</li>
<li><a href="/blog/python-advanced/05-c-extensions/case-studies/cython-markdown/" data-link-title="案例：Cython 加速 Markdown 解析" data-link-desc="用 Cython 加速 Markdown 連結解析器，比較純 Python 與 Cython 的效能差異">5.1 Cython 加速</a></li>
</ul>
<h2 id="問題背景">問題背景</h2>
<h3 id="現有設計">現有設計</h3>
<p><code>markdown_link_checker.py</code> 使用純 Python 的正則表達式解析 Markdown 連結：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">class</span> <span class="nc">MarkdownLinkChecker</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Markdown 連結檢查器&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="c1"># Markdown 連結正則表達式</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="c1"># 匹配 [text](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/target) 格式，排除圖片 ![alt](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/src)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">INLINE_LINK_PATTERN</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="sa">r</span><span class="s1">&#39;(?&lt;!!)\[([^\]]+)\]\(([^)]+)\)&#39;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="c1"># 引用式連結定義 [ref]: target</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">REFERENCE_DEF_PATTERN</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="sa">r</span><span class="s1">&#39;^\s*\[([^\]]+)\]:\s*(.+)$&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="n">re</span><span class="o">.</span><span class="n">MULTILINE</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="c1"># 引用式連結使用 [text][ref]</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="n">REFERENCE_USE_PATTERN</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="sa">r</span><span class="s1">&#39;\[([^\]]+)\]\[([^\]]+)\]&#39;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="k">def</span> <span class="nf">parse_markdown_links</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="s2">        解析 Markdown 內容中的所有連結
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="s2">        Args:
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="s2">            content: Markdown 內容
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="s2">        Returns:
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="s2">            list[dict]: 連結列表，每個包含 text, target, line
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="n">links</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">        <span class="n">lines</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">
</span></span><span class="line"><span class="ln">37</span><span class="cl">        <span class="c1"># 首先收集引用式連結定義</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">        <span class="n">reference_defs</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">        <span class="k">for</span> <span class="k">match</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">REFERENCE_DEF_PATTERN</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="n">content</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">            <span class="n">ref_name</span> <span class="o">=</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">            <span class="n">ref_target</span> <span class="o">=</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">            <span class="n">reference_defs</span><span class="p">[</span><span class="n">ref_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">ref_target</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">
</span></span><span class="line"><span class="ln">44</span><span class="cl">        <span class="c1"># 追蹤是否在程式碼區塊內</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">        <span class="n">in_code_block</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">
</span></span><span class="line"><span class="ln">47</span><span class="cl">        <span class="c1"># 解析行內連結</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">        <span class="k">for</span> <span class="n">line_num</span><span class="p">,</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">lines</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">            <span class="c1"># 檢查程式碼區塊開始/結束</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl">            <span class="k">if</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;```&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">                <span class="n">in_code_block</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">in_code_block</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl">
</span></span><span class="line"><span class="ln">54</span><span class="cl">            <span class="c1"># 跳過程式碼區塊內的連結</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl">            <span class="k">if</span> <span class="n">in_code_block</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl">
</span></span><span class="line"><span class="ln">58</span><span class="cl">            <span class="c1"># 行內連結 [text](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/target)</span>
</span></span><span class="line"><span class="ln">59</span><span class="cl">            <span class="k">for</span> <span class="k">match</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">INLINE_LINK_PATTERN</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="n">line</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">60</span><span class="cl">                <span class="n">links</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">61</span><span class="cl">                    <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">62</span><span class="cl">                    <span class="s2">&#34;target&#34;</span><span class="p">:</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">63</span><span class="cl">                    <span class="s2">&#34;line&#34;</span><span class="p">:</span> <span class="n">line_num</span>
</span></span><span class="line"><span class="ln">64</span><span class="cl">                <span class="p">})</span>
</span></span><span class="line"><span class="ln">65</span><span class="cl">
</span></span><span class="line"><span class="ln">66</span><span class="cl">            <span class="c1"># 引用式連結 [text][ref]</span>
</span></span><span class="line"><span class="ln">67</span><span class="cl">            <span class="k">for</span> <span class="k">match</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">REFERENCE_USE_PATTERN</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="n">line</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">68</span><span class="cl">                <span class="n">ref_name</span> <span class="o">=</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">69</span><span class="cl">                <span class="k">if</span> <span class="n">ref_name</span> <span class="ow">in</span> <span class="n">reference_defs</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">70</span><span class="cl">                    <span class="n">links</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">71</span><span class="cl">                        <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">72</span><span class="cl">                        <span class="s2">&#34;target&#34;</span><span class="p">:</span> <span class="n">reference_defs</span><span class="p">[</span><span class="n">ref_name</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">73</span><span class="cl">                        <span class="s2">&#34;line&#34;</span><span class="p">:</span> <span class="n">line_num</span>
</span></span><span class="line"><span class="ln">74</span><span class="cl">                    <span class="p">})</span>
</span></span><span class="line"><span class="ln">75</span><span class="cl">
</span></span><span class="line"><span class="ln">76</span><span class="cl">        <span class="k">return</span> <span class="n">links</span></span></span></code></pre></div><p>這段程式碼的核心瓶頸：</p>
<ol>
<li><strong>正則表達式解析</strong>：Python 的 <code>re</code> 模組效能有限</li>
<li><strong>字串分割與迭代</strong>：大量的記憶體配置</li>
<li><strong>字典操作</strong>：每個連結都建立新字典</li>
</ol>
<h3 id="為什麼選擇-rust">為什麼選擇 Rust？</h3>
<p>相比 Cython：</p>
<table>
  <thead>
      <tr>
          <th>面向</th>
          <th>Cython</th>
          <th>Rust (PyO3)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>記憶體安全</td>
          <td>依賴 GC</td>
          <td>編譯時保證</td>
      </tr>
      <tr>
          <td>正則表達式</td>
          <td>仍用 Python re</td>
          <td>原生 regex crate</td>
      </tr>
      <tr>
          <td>錯誤處理</td>
          <td>例外機制</td>
          <td>Result 類型</td>
      </tr>
      <tr>
          <td>多執行緒</td>
          <td>受 GIL 限制</td>
          <td>可完全繞過 GIL</td>
      </tr>
      <tr>
          <td>生態系統</td>
          <td>有限</td>
          <td>豐富的 Cargo 生態</td>
      </tr>
  </tbody>
</table>
<h2 id="進階解決方案">進階解決方案</h2>
<h3 id="設計目標">設計目標</h3>
<ol>
<li>用 Rust 重寫核心解析邏輯</li>
<li>保持 Python API 相容</li>
<li>實現顯著的效能提升</li>
</ol>
<h3 id="實作步驟">實作步驟</h3>
<h4 id="步驟-1建立-rust-專案結構">步驟 1：建立 Rust 專案結構</h4>
<p>首先，使用 Maturin 建立新專案：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 安裝 maturin（如果尚未安裝）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">pip install maturin
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 建立新專案</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">mkdir markdown_parser_rs
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nb">cd</span> markdown_parser_rs
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># 初始化 maturin 專案（選擇 pyo3 作為綁定）</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">maturin init --bindings pyo3
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># 專案結構如下：</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># markdown_parser_rs/</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"># ├── Cargo.toml</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"># ├── pyproject.toml</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"># └── src/</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1">#     └── lib.rs</span></span></span></code></pre></div><p>接著，編輯 <code>Cargo.toml</code> 加入必要的依賴：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">package</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;markdown_parser_rs&#34;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">edition</span> <span class="p">=</span> <span class="s2">&#34;2021&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">lib</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;markdown_parser_rs&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">crate-type</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;cdylib&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.22&#34;</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">regex</span> <span class="p">=</span> <span class="s2">&#34;1.11&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">once_cell</span> <span class="p">=</span> <span class="s2">&#34;1.20&#34;</span></span></span></code></pre></div><h4 id="步驟-2實作-rust-解析函式">步驟 2：實作 Rust 解析函式</h4>
<p>先定義核心的資料結構和解析邏輯：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// src/lib.rs
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">once_cell</span>::<span class="n">sync</span>::<span class="n">Lazy</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">regex</span>::<span class="n">Regex</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="sd">/// Represents a parsed markdown link
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="sd"></span><span class="cp">#[derive(Debug, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">MarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">text</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">target</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">line</span>: <span class="kt">usize</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span><span class="c1">// Pre-compiled regex patterns (compile once, use many times)
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"></span><span class="k">static</span><span class="w"> </span><span class="no">INLINE_LINK_PATTERN</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="c1">// Match [text](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/target), excluding images ![alt](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/src)
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;(?&lt;!!)\[([^\]]+)\]\(([^)]+)\)&#34;</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">REFERENCE_DEF_PATTERN</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">    </span><span class="c1">// Match [ref]: target
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;(?m)^\s*\[([^\]]+)\]:\s*(.+)$&#34;</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">REFERENCE_USE_PATTERN</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="c1">// Match [text][ref]
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;\[([^\]]+)\]\[([^\]]+)\]&#34;</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w"></span><span class="sd">/// Parse markdown content and extract all links
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="sd"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">parse_links</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">MarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">links</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">    </span><span class="c1">// First, collect reference definitions
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">reference_defs</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">cap</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="no">REFERENCE_DEF_PATTERN</span><span class="p">.</span><span class="n">captures_iter</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">ref_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">to_lowercase</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">ref_target</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">trim</span><span class="p">().</span><span class="n">to_string</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">        </span><span class="n">reference_defs</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">ref_name</span><span class="p">,</span><span class="w"> </span><span class="n">ref_target</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">    </span><span class="c1">// Track code block state
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">in_code_block</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">    </span><span class="c1">// Parse line by line
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">line_num</span><span class="p">,</span><span class="w"> </span><span class="n">line</span><span class="p">)</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">content</span><span class="p">.</span><span class="n">lines</span><span class="p">().</span><span class="n">enumerate</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">line_number</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">line_num</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 1-indexed
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">        </span><span class="c1">// Check for code block markers
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="n">line</span><span class="p">.</span><span class="n">trim_start</span><span class="p">().</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;```&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">            </span><span class="n">in_code_block</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">!</span><span class="n">in_code_block</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">            </span><span class="k">continue</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w">        </span><span class="c1">// Skip content inside code blocks
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="n">in_code_block</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="w">            </span><span class="k">continue</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="w">        </span><span class="c1">// Parse inline links [text](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/target)
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">cap</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="no">INLINE_LINK_PATTERN</span><span class="p">.</span><span class="n">captures_iter</span><span class="p">(</span><span class="n">line</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="w">            </span><span class="n">links</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">MarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="w">                </span><span class="n">text</span>: <span class="nc">cap</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="w">                </span><span class="n">target</span>: <span class="nc">cap</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">65</span><span class="cl"><span class="w">                </span><span class="n">line</span>: <span class="nc">line_number</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="w">            </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">67</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">69</span><span class="cl"><span class="w">        </span><span class="c1">// Parse reference links [text][ref]
</span></span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">cap</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="no">REFERENCE_USE_PATTERN</span><span class="p">.</span><span class="n">captures_iter</span><span class="p">(</span><span class="n">line</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">71</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">ref_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">to_lowercase</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">72</span><span class="cl"><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">target</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reference_defs</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ref_name</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">73</span><span class="cl"><span class="w">                </span><span class="n">links</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">MarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">74</span><span class="cl"><span class="w">                    </span><span class="n">text</span>: <span class="nc">cap</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">75</span><span class="cl"><span class="w">                    </span><span class="n">target</span>: <span class="nc">target</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">76</span><span class="cl"><span class="w">                    </span><span class="n">line</span>: <span class="nc">line_number</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">77</span><span class="cl"><span class="w">                </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">78</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">79</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">80</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">81</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">82</span><span class="cl"><span class="w">    </span><span class="n">links</span><span class="w">
</span></span></span><span class="line"><span class="ln">83</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h4 id="步驟-3用-pyo3-導出-python-介面">步驟 3：用 PyO3 導出 Python 介面</h4>
<p>將 Rust 結構與函式導出給 Python 使用：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln">  1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">types</span>::<span class="n">PyDict</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="w"></span><span class="sd">/// Python-visible link structure
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="sd"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">  7</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">text</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">target</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 13</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">line</span>: <span class="kt">usize</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 14</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 15</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 17</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 18</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 19</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="w">            </span><span class="s">&#34;MarkdownLink(text=&#39;</span><span class="si">{}</span><span class="s">&#39;, target=&#39;</span><span class="si">{}</span><span class="s">&#39;, line=</span><span class="si">{}</span><span class="s">)&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 21</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">text</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">target</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">line</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 22</span><span class="cl"><span class="w">        </span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 23</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 24</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 25</span><span class="cl"><span class="w">    </span><span class="sd">/// Convert to Python dict for compatibility
</span></span></span><span class="line"><span class="ln"> 26</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">to_dict</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Bound</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="p">,</span><span class="w"> </span><span class="n">PyDict</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 27</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">dict</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyDict</span>::<span class="n">new</span><span class="p">(</span><span class="n">py</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="w">        </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;text&#34;</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">text</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="w">        </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;target&#34;</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">target</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="w">        </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;line&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">line</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 31</span><span class="cl"><span class="w">        </span><span class="n">dict</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 32</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 33</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 35</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="nb">From</span><span class="o">&lt;</span><span class="n">MarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 36</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">from</span><span class="p">(</span><span class="n">link</span>: <span class="nc">MarkdownLink</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 37</span><span class="cl"><span class="w">        </span><span class="n">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 38</span><span class="cl"><span class="w">            </span><span class="n">text</span>: <span class="nc">link</span><span class="p">.</span><span class="n">text</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 39</span><span class="cl"><span class="w">            </span><span class="n">target</span>: <span class="nc">link</span><span class="p">.</span><span class="n">target</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="w">            </span><span class="n">line</span>: <span class="nc">link</span><span class="p">.</span><span class="n">line</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 42</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 43</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 44</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 45</span><span class="cl"><span class="w"></span><span class="sd">/// Parse markdown content and return list of links as objects
</span></span></span><span class="line"><span class="ln"> 46</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 47</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parse_markdown_links</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 48</span><span class="cl"><span class="w">    </span><span class="n">parse_links</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 49</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">into_iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 50</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="n">PyMarkdownLink</span>::<span class="n">from</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 52</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="w"></span><span class="sd">/// Parse markdown content and return list of links as dicts
</span></span></span><span class="line"><span class="ln"> 55</span><span class="cl"><span class="sd">/// (for drop-in compatibility with existing Python code)
</span></span></span><span class="line"><span class="ln"> 56</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 57</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parse_markdown_links_as_dicts</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 58</span><span class="cl"><span class="w">    </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 59</span><span class="cl"><span class="w">    </span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 60</span><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Bound</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="p">,</span><span class="w"> </span><span class="n">PyDict</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 61</span><span class="cl"><span class="w">    </span><span class="n">parse_links</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 62</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">into_iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 63</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">link</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 64</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">dict</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyDict</span>::<span class="n">new</span><span class="p">(</span><span class="n">py</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 65</span><span class="cl"><span class="w">            </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;text&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">link</span><span class="p">.</span><span class="n">text</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 66</span><span class="cl"><span class="w">            </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;target&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">link</span><span class="p">.</span><span class="n">target</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 67</span><span class="cl"><span class="w">            </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;line&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">link</span><span class="p">.</span><span class="n">line</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 68</span><span class="cl"><span class="w">            </span><span class="n">dict</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 69</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 70</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 71</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 73</span><span class="cl"><span class="w"></span><span class="sd">/// Filter out external links, keeping only internal links
</span></span></span><span class="line"><span class="ln"> 74</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 75</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">filter_internal_links</span><span class="p">(</span><span class="n">links</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 76</span><span class="cl"><span class="w">    </span><span class="n">links</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 77</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">into_iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 78</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">link</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 79</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">target</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">link</span><span class="p">.</span><span class="n">target</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 80</span><span class="cl"><span class="w">            </span><span class="c1">// Skip pure anchor links
</span></span></span><span class="line"><span class="ln"> 81</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="sc">&#39;#&#39;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 82</span><span class="cl"><span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 83</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 84</span><span class="cl"><span class="w">            </span><span class="c1">// Skip external links
</span></span></span><span class="line"><span class="ln"> 85</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;http://&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 86</span><span class="cl"><span class="w">                </span><span class="o">||</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;https://&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 87</span><span class="cl"><span class="w">                </span><span class="o">||</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;mailto:&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 88</span><span class="cl"><span class="w">                </span><span class="o">||</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;tel:&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 89</span><span class="cl"><span class="w">                </span><span class="o">||</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;ftp://&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 90</span><span class="cl"><span class="w">            </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 91</span><span class="cl"><span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 92</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 93</span><span class="cl"><span class="w">            </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 94</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 95</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 96</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 97</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 98</span><span class="cl"><span class="w"></span><span class="sd">/// Python module definition
</span></span></span><span class="line"><span class="ln"> 99</span><span class="cl"><span class="sd"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">100</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">markdown_parser_rs</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">101</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">102</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">parse_markdown_links</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">103</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">parse_markdown_links_as_dicts</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">104</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">filter_internal_links</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">105</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">106</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h4 id="步驟-4建置與測試">步驟 4：建置與測試</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 開發模式建置（快速，用於測試）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">maturin develop
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 或者以 release 模式建置（優化效能）</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">maturin develop --release
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 建置 wheel 套件</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">maturin build --release
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 安裝到當前環境</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">pip install target/wheels/markdown_parser_rs-*.whl</span></span></code></pre></div><h3 id="完整程式碼">完整程式碼</h3>
<p>以下是完整的 <code>src/lib.rs</code>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln">  1</span><span class="cl"><span class="sd">//! Markdown Link Parser - A high-performance parser written in Rust
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="sd">//!
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="sd">//! This module provides fast markdown link parsing capabilities
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="sd">//! using Rust&#39;s regex crate and PyO3 for Python bindings.
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="sd"></span><span class="w">
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">once_cell</span>::<span class="n">sync</span>::<span class="n">Lazy</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  7</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">types</span>::<span class="n">PyDict</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">regex</span>::<span class="n">Regex</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 13</span><span class="cl"><span class="c1">// Core Data Structures
</span></span></span><span class="line"><span class="ln"> 14</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 15</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="w"></span><span class="sd">/// Internal link representation
</span></span></span><span class="line"><span class="ln"> 17</span><span class="cl"><span class="sd"></span><span class="cp">#[derive(Debug, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 18</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">MarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 19</span><span class="cl"><span class="w">    </span><span class="n">text</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="w">    </span><span class="n">target</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 21</span><span class="cl"><span class="w">    </span><span class="n">line</span>: <span class="kt">usize</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 22</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 23</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 24</span><span class="cl"><span class="w"></span><span class="sd">/// Python-visible link structure with getter methods
</span></span></span><span class="line"><span class="ln"> 25</span><span class="cl"><span class="sd"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 26</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 27</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">text</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 31</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">target</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 32</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 33</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">line</span>: <span class="kt">usize</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 35</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 36</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 37</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 38</span><span class="cl"><span class="w">    </span><span class="sd">/// String representation for debugging
</span></span></span><span class="line"><span class="ln"> 39</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="w">            </span><span class="s">&#34;MarkdownLink(text=&#39;</span><span class="si">{}</span><span class="s">&#39;, target=&#39;</span><span class="si">{}</span><span class="s">&#39;, line=</span><span class="si">{}</span><span class="s">)&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 42</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">text</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">target</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">line</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 43</span><span class="cl"><span class="w">        </span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 44</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 45</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 46</span><span class="cl"><span class="w">    </span><span class="sd">/// Convert to Python dict for compatibility with existing code
</span></span></span><span class="line"><span class="ln"> 47</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">to_dict</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Bound</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="p">,</span><span class="w"> </span><span class="n">PyDict</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 48</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">dict</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyDict</span>::<span class="n">new</span><span class="p">(</span><span class="n">py</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 49</span><span class="cl"><span class="w">        </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;text&#34;</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">text</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 50</span><span class="cl"><span class="w">        </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;target&#34;</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">target</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="w">        </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;line&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">line</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 52</span><span class="cl"><span class="w">        </span><span class="n">dict</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 55</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 56</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="nb">From</span><span class="o">&lt;</span><span class="n">MarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 57</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">from</span><span class="p">(</span><span class="n">link</span>: <span class="nc">MarkdownLink</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 58</span><span class="cl"><span class="w">        </span><span class="n">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 59</span><span class="cl"><span class="w">            </span><span class="n">text</span>: <span class="nc">link</span><span class="p">.</span><span class="n">text</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 60</span><span class="cl"><span class="w">            </span><span class="n">target</span>: <span class="nc">link</span><span class="p">.</span><span class="n">target</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 61</span><span class="cl"><span class="w">            </span><span class="n">line</span>: <span class="nc">link</span><span class="p">.</span><span class="n">line</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 62</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 63</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 64</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 65</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 66</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 67</span><span class="cl"><span class="c1">// Pre-compiled Regex Patterns
</span></span></span><span class="line"><span class="ln"> 68</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 69</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 70</span><span class="cl"><span class="w"></span><span class="c1">// Inline link: [text](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/target), excluding images ![alt](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/src)
</span></span></span><span class="line"><span class="ln"> 71</span><span class="cl"><span class="c1"></span><span class="k">static</span><span class="w"> </span><span class="no">INLINE_LINK_PATTERN</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;(?&lt;!!)\[([^\]]+)\]\(([^)]+)\)&#34;</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 73</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 74</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 75</span><span class="cl"><span class="w"></span><span class="c1">// Reference definition: [ref]: target
</span></span></span><span class="line"><span class="ln"> 76</span><span class="cl"><span class="c1"></span><span class="k">static</span><span class="w"> </span><span class="no">REFERENCE_DEF_PATTERN</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 77</span><span class="cl"><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;(?m)^\s*\[([^\]]+)\]:\s*(.+)$&#34;</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 78</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 79</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 80</span><span class="cl"><span class="w"></span><span class="c1">// Reference usage: [text][ref]
</span></span></span><span class="line"><span class="ln"> 81</span><span class="cl"><span class="c1"></span><span class="k">static</span><span class="w"> </span><span class="no">REFERENCE_USE_PATTERN</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 82</span><span class="cl"><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;\[([^\]]+)\]\[([^\]]+)\]&#34;</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 83</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 84</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 85</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 86</span><span class="cl"><span class="c1">// Core Parsing Logic
</span></span></span><span class="line"><span class="ln"> 87</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 88</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 89</span><span class="cl"><span class="w"></span><span class="sd">/// Parse markdown content and extract all links
</span></span></span><span class="line"><span class="ln"> 90</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln"> 91</span><span class="cl"><span class="sd">/// This function handles:
</span></span></span><span class="line"><span class="ln"> 92</span><span class="cl"><span class="sd">/// - Inline links: [text](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/url)
</span></span></span><span class="line"><span class="ln"> 93</span><span class="cl"><span class="sd">/// - Reference links: [text][ref] with [ref]: url definitions
</span></span></span><span class="line"><span class="ln"> 94</span><span class="cl"><span class="sd">/// - Code block detection (skips links inside ```)
</span></span></span><span class="line"><span class="ln"> 95</span><span class="cl"><span class="sd"></span><span class="k">fn</span> <span class="nf">parse_links</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">MarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 96</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">links</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 97</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 98</span><span class="cl"><span class="w">    </span><span class="c1">// Phase 1: Collect all reference definitions
</span></span></span><span class="line"><span class="ln"> 99</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">reference_defs</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">100</span><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">cap</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="no">REFERENCE_DEF_PATTERN</span><span class="p">.</span><span class="n">captures_iter</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">101</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">ref_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">to_lowercase</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">102</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">ref_target</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">trim</span><span class="p">().</span><span class="n">to_string</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">103</span><span class="cl"><span class="w">        </span><span class="n">reference_defs</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">ref_name</span><span class="p">,</span><span class="w"> </span><span class="n">ref_target</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">104</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">105</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">106</span><span class="cl"><span class="w">    </span><span class="c1">// Phase 2: Parse links line by line
</span></span></span><span class="line"><span class="ln">107</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">in_code_block</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">108</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">109</span><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">line_num</span><span class="p">,</span><span class="w"> </span><span class="n">line</span><span class="p">)</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">content</span><span class="p">.</span><span class="n">lines</span><span class="p">().</span><span class="n">enumerate</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">110</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">line_number</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">line_num</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// Convert to 1-indexed
</span></span></span><span class="line"><span class="ln">111</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">112</span><span class="cl"><span class="w">        </span><span class="c1">// Toggle code block state
</span></span></span><span class="line"><span class="ln">113</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="n">line</span><span class="p">.</span><span class="n">trim_start</span><span class="p">().</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;```&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">114</span><span class="cl"><span class="w">            </span><span class="n">in_code_block</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">!</span><span class="n">in_code_block</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">115</span><span class="cl"><span class="w">            </span><span class="k">continue</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">116</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">117</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">118</span><span class="cl"><span class="w">        </span><span class="c1">// Skip content inside code blocks
</span></span></span><span class="line"><span class="ln">119</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="n">in_code_block</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">120</span><span class="cl"><span class="w">            </span><span class="k">continue</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">121</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">122</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">123</span><span class="cl"><span class="w">        </span><span class="c1">// Extract inline links
</span></span></span><span class="line"><span class="ln">124</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">cap</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="no">INLINE_LINK_PATTERN</span><span class="p">.</span><span class="n">captures_iter</span><span class="p">(</span><span class="n">line</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">125</span><span class="cl"><span class="w">            </span><span class="n">links</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">MarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">126</span><span class="cl"><span class="w">                </span><span class="n">text</span>: <span class="nc">cap</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">127</span><span class="cl"><span class="w">                </span><span class="n">target</span>: <span class="nc">cap</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">128</span><span class="cl"><span class="w">                </span><span class="n">line</span>: <span class="nc">line_number</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">129</span><span class="cl"><span class="w">            </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">130</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">131</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">132</span><span class="cl"><span class="w">        </span><span class="c1">// Extract reference-style links
</span></span></span><span class="line"><span class="ln">133</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">cap</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="no">REFERENCE_USE_PATTERN</span><span class="p">.</span><span class="n">captures_iter</span><span class="p">(</span><span class="n">line</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">134</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">ref_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">to_lowercase</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">135</span><span class="cl"><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">target</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reference_defs</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ref_name</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">136</span><span class="cl"><span class="w">                </span><span class="n">links</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">MarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">137</span><span class="cl"><span class="w">                    </span><span class="n">text</span>: <span class="nc">cap</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">138</span><span class="cl"><span class="w">                    </span><span class="n">target</span>: <span class="nc">target</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">139</span><span class="cl"><span class="w">                    </span><span class="n">line</span>: <span class="nc">line_number</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">140</span><span class="cl"><span class="w">                </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">141</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">142</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">143</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">144</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">145</span><span class="cl"><span class="w">    </span><span class="n">links</span><span class="w">
</span></span></span><span class="line"><span class="ln">146</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">147</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">148</span><span class="cl"><span class="w"></span><span class="sd">/// Check if a link target is external
</span></span></span><span class="line"><span class="ln">149</span><span class="cl"><span class="sd"></span><span class="k">fn</span> <span class="nf">is_external_link</span><span class="p">(</span><span class="n">target</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">150</span><span class="cl"><span class="w">    </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;http://&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">151</span><span class="cl"><span class="w">        </span><span class="o">||</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;https://&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">152</span><span class="cl"><span class="w">        </span><span class="o">||</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;mailto:&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">153</span><span class="cl"><span class="w">        </span><span class="o">||</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;tel:&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">154</span><span class="cl"><span class="w">        </span><span class="o">||</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;ftp://&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">155</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">156</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">157</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln">158</span><span class="cl"><span class="c1">// Python Interface Functions
</span></span></span><span class="line"><span class="ln">159</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln">160</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">161</span><span class="cl"><span class="w"></span><span class="sd">/// Parse markdown content and return a list of MarkdownLink objects
</span></span></span><span class="line"><span class="ln">162</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">163</span><span class="cl"><span class="sd">/// Args:
</span></span></span><span class="line"><span class="ln">164</span><span class="cl"><span class="sd">///     content: The markdown content to parse
</span></span></span><span class="line"><span class="ln">165</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">166</span><span class="cl"><span class="sd">/// Returns:
</span></span></span><span class="line"><span class="ln">167</span><span class="cl"><span class="sd">///     List of MarkdownLink objects
</span></span></span><span class="line"><span class="ln">168</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">169</span><span class="cl"><span class="sd">/// Example:
</span></span></span><span class="line"><span class="ln">170</span><span class="cl"><span class="sd">///     &gt;&gt;&gt; links = parse_markdown_links(&#34;Check [docs](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/README.md)&#34;)
</span></span></span><span class="line"><span class="ln">171</span><span class="cl"><span class="sd">///     &gt;&gt;&gt; links[0].text
</span></span></span><span class="line"><span class="ln">172</span><span class="cl"><span class="sd">///     &#39;docs&#39;
</span></span></span><span class="line"><span class="ln">173</span><span class="cl"><span class="sd">///     &gt;&gt;&gt; links[0].target
</span></span></span><span class="line"><span class="ln">174</span><span class="cl"><span class="sd">///     &#39;./README.md&#39;
</span></span></span><span class="line"><span class="ln">175</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">176</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parse_markdown_links</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">177</span><span class="cl"><span class="w">    </span><span class="n">parse_links</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">178</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">into_iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">179</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="n">PyMarkdownLink</span>::<span class="n">from</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">180</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">181</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">182</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">183</span><span class="cl"><span class="w"></span><span class="sd">/// Parse markdown content and return a list of dicts
</span></span></span><span class="line"><span class="ln">184</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">185</span><span class="cl"><span class="sd">/// This function provides drop-in compatibility with the original
</span></span></span><span class="line"><span class="ln">186</span><span class="cl"><span class="sd">/// Python implementation that returns dicts.
</span></span></span><span class="line"><span class="ln">187</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">188</span><span class="cl"><span class="sd">/// Args:
</span></span></span><span class="line"><span class="ln">189</span><span class="cl"><span class="sd">///     content: The markdown content to parse
</span></span></span><span class="line"><span class="ln">190</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">191</span><span class="cl"><span class="sd">/// Returns:
</span></span></span><span class="line"><span class="ln">192</span><span class="cl"><span class="sd">///     List of dicts with keys: text, target, line
</span></span></span><span class="line"><span class="ln">193</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">194</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parse_markdown_links_as_dicts</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">195</span><span class="cl"><span class="w">    </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">196</span><span class="cl"><span class="w">    </span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">197</span><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Bound</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="p">,</span><span class="w"> </span><span class="n">PyDict</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">198</span><span class="cl"><span class="w">    </span><span class="n">parse_links</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">199</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">into_iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">200</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">link</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">201</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">dict</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyDict</span>::<span class="n">new</span><span class="p">(</span><span class="n">py</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">202</span><span class="cl"><span class="w">            </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;text&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">link</span><span class="p">.</span><span class="n">text</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">203</span><span class="cl"><span class="w">            </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;target&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">link</span><span class="p">.</span><span class="n">target</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">204</span><span class="cl"><span class="w">            </span><span class="n">dict</span><span class="p">.</span><span class="n">set_item</span><span class="p">(</span><span class="s">&#34;line&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">link</span><span class="p">.</span><span class="n">line</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">205</span><span class="cl"><span class="w">            </span><span class="n">dict</span><span class="w">
</span></span></span><span class="line"><span class="ln">206</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">207</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">208</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">209</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">210</span><span class="cl"><span class="w"></span><span class="sd">/// Filter links to keep only internal ones
</span></span></span><span class="line"><span class="ln">211</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">212</span><span class="cl"><span class="sd">/// Removes:
</span></span></span><span class="line"><span class="ln">213</span><span class="cl"><span class="sd">/// - External links (http://, https://, mailto:, etc.)
</span></span></span><span class="line"><span class="ln">214</span><span class="cl"><span class="sd">/// - Pure anchor links (#section)
</span></span></span><span class="line"><span class="ln">215</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">216</span><span class="cl"><span class="sd">/// Args:
</span></span></span><span class="line"><span class="ln">217</span><span class="cl"><span class="sd">///     links: List of MarkdownLink objects
</span></span></span><span class="line"><span class="ln">218</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">219</span><span class="cl"><span class="sd">/// Returns:
</span></span></span><span class="line"><span class="ln">220</span><span class="cl"><span class="sd">///     Filtered list of internal links
</span></span></span><span class="line"><span class="ln">221</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">222</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">filter_internal_links</span><span class="p">(</span><span class="n">links</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">223</span><span class="cl"><span class="w">    </span><span class="n">links</span><span class="w">
</span></span></span><span class="line"><span class="ln">224</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">into_iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">225</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">link</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">226</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">target</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">link</span><span class="p">.</span><span class="n">target</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">227</span><span class="cl"><span class="w">            </span><span class="c1">// Skip pure anchor links
</span></span></span><span class="line"><span class="ln">228</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="sc">&#39;#&#39;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">229</span><span class="cl"><span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">230</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">231</span><span class="cl"><span class="w">            </span><span class="c1">// Skip external links
</span></span></span><span class="line"><span class="ln">232</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="o">!</span><span class="n">is_external_link</span><span class="p">(</span><span class="n">target</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">233</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">234</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">235</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">236</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">237</span><span class="cl"><span class="w"></span><span class="sd">/// Count total links in content (fast path, no object creation)
</span></span></span><span class="line"><span class="ln">238</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">239</span><span class="cl"><span class="sd">/// Args:
</span></span></span><span class="line"><span class="ln">240</span><span class="cl"><span class="sd">///     content: The markdown content to parse
</span></span></span><span class="line"><span class="ln">241</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">242</span><span class="cl"><span class="sd">/// Returns:
</span></span></span><span class="line"><span class="ln">243</span><span class="cl"><span class="sd">///     Number of links found
</span></span></span><span class="line"><span class="ln">244</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">245</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">count_links</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">246</span><span class="cl"><span class="w">    </span><span class="n">parse_links</span><span class="p">(</span><span class="n">content</span><span class="p">).</span><span class="n">len</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">247</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">248</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">249</span><span class="cl"><span class="w"></span><span class="sd">/// Parse and filter in one pass (most efficient for link checking)
</span></span></span><span class="line"><span class="ln">250</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">251</span><span class="cl"><span class="sd">/// Args:
</span></span></span><span class="line"><span class="ln">252</span><span class="cl"><span class="sd">///     content: The markdown content to parse
</span></span></span><span class="line"><span class="ln">253</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">254</span><span class="cl"><span class="sd">/// Returns:
</span></span></span><span class="line"><span class="ln">255</span><span class="cl"><span class="sd">///     List of internal MarkdownLink objects
</span></span></span><span class="line"><span class="ln">256</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">257</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parse_internal_links</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">258</span><span class="cl"><span class="w">    </span><span class="n">parse_links</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">259</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">into_iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">260</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">link</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">261</span><span class="cl"><span class="w">            </span><span class="o">!</span><span class="n">link</span><span class="p">.</span><span class="n">target</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="sc">&#39;#&#39;</span><span class="p">)</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="o">!</span><span class="n">is_external_link</span><span class="p">(</span><span class="o">&amp;</span><span class="n">link</span><span class="p">.</span><span class="n">target</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">262</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">263</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="n">PyMarkdownLink</span>::<span class="n">from</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">264</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">265</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">266</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">267</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln">268</span><span class="cl"><span class="c1">// Module Definition
</span></span></span><span class="line"><span class="ln">269</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln">270</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">271</span><span class="cl"><span class="w"></span><span class="sd">/// High-performance Markdown link parser
</span></span></span><span class="line"><span class="ln">272</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">273</span><span class="cl"><span class="sd">/// This module provides Rust-powered functions for parsing
</span></span></span><span class="line"><span class="ln">274</span><span class="cl"><span class="sd">/// and filtering markdown links.
</span></span></span><span class="line"><span class="ln">275</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">276</span><span class="cl"><span class="sd">/// Functions:
</span></span></span><span class="line"><span class="ln">277</span><span class="cl"><span class="sd">///     parse_markdown_links: Parse content, return MarkdownLink objects
</span></span></span><span class="line"><span class="ln">278</span><span class="cl"><span class="sd">///     parse_markdown_links_as_dicts: Parse content, return dicts
</span></span></span><span class="line"><span class="ln">279</span><span class="cl"><span class="sd">///     parse_internal_links: Parse and filter to internal links only
</span></span></span><span class="line"><span class="ln">280</span><span class="cl"><span class="sd">///     filter_internal_links: Filter existing links
</span></span></span><span class="line"><span class="ln">281</span><span class="cl"><span class="sd">///     count_links: Fast link counting
</span></span></span><span class="line"><span class="ln">282</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">283</span><span class="cl"><span class="sd">/// Classes:
</span></span></span><span class="line"><span class="ln">284</span><span class="cl"><span class="sd">///     MarkdownLink: Represents a parsed link
</span></span></span><span class="line"><span class="ln">285</span><span class="cl"><span class="sd"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">286</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">markdown_parser_rs</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">287</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">288</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">parse_markdown_links</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">289</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">parse_markdown_links_as_dicts</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">290</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">filter_internal_links</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">291</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">count_links</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">292</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">parse_internal_links</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">293</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">294</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="python-整合範例">Python 整合範例</h3>
<p>以下展示如何在現有程式碼中整合 Rust 模組：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">  1</span><span class="cl"><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="s2">使用 Rust 加速的 Markdown 連結檢查器
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="s2">這個範例展示如何用 Rust 模組替換原有的 Python 解析邏輯，
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="s2">同時保持 API 相容性。
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">  7</span><span class="cl">
</span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Optional</span>
</span></span><span class="line"><span class="ln"> 10</span><span class="cl">
</span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="c1"># Try to import Rust module, fallback to pure Python</span>
</span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 13</span><span class="cl">    <span class="kn">import</span> <span class="nn">markdown_parser_rs</span> <span class="k">as</span> <span class="nn">parser_rs</span>
</span></span><span class="line"><span class="ln"> 14</span><span class="cl">    <span class="n">USE_RUST</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="ln"> 15</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Using Rust-powered parser&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 17</span><span class="cl">    <span class="n">USE_RUST</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="ln"> 18</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Rust module not available, using pure Python&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 19</span><span class="cl">
</span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="k">class</span> <span class="nc">MarkdownLinkChecker</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 21</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Markdown link checker with optional Rust acceleration&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 22</span><span class="cl">
</span></span><span class="line"><span class="ln"> 23</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">use_rust</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 24</span><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 25</span><span class="cl"><span class="s2">        Initialize the checker
</span></span></span><span class="line"><span class="ln"> 26</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln"> 27</span><span class="cl"><span class="s2">        Args:
</span></span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="s2">            use_rust: Whether to use Rust module if available
</span></span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 30</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">use_rust</span> <span class="o">=</span> <span class="n">use_rust</span> <span class="ow">and</span> <span class="n">USE_RUST</span>
</span></span><span class="line"><span class="ln"> 31</span><span class="cl">
</span></span><span class="line"><span class="ln"> 32</span><span class="cl">    <span class="k">def</span> <span class="nf">parse_markdown_links</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 33</span><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="s2">        Parse markdown content and extract all links
</span></span></span><span class="line"><span class="ln"> 35</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln"> 36</span><span class="cl"><span class="s2">        Args:
</span></span></span><span class="line"><span class="ln"> 37</span><span class="cl"><span class="s2">            content: Markdown content
</span></span></span><span class="line"><span class="ln"> 38</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln"> 39</span><span class="cl"><span class="s2">        Returns:
</span></span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="s2">            List of dicts with keys: text, target, line
</span></span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 42</span><span class="cl">        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">use_rust</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 43</span><span class="cl">            <span class="c1"># Use Rust implementation</span>
</span></span><span class="line"><span class="ln"> 44</span><span class="cl">            <span class="k">return</span> <span class="n">parser_rs</span><span class="o">.</span><span class="n">parse_markdown_links_as_dicts</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 45</span><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 46</span><span class="cl">            <span class="c1"># Fallback to pure Python (original implementation)</span>
</span></span><span class="line"><span class="ln"> 47</span><span class="cl">            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_parse_python</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 48</span><span class="cl">
</span></span><span class="line"><span class="ln"> 49</span><span class="cl">    <span class="k">def</span> <span class="nf">parse_internal_links</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 50</span><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="s2">        Parse and filter to internal links only
</span></span></span><span class="line"><span class="ln"> 52</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="s2">        Args:
</span></span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="s2">            content: Markdown content
</span></span></span><span class="line"><span class="ln"> 55</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln"> 56</span><span class="cl"><span class="s2">        Returns:
</span></span></span><span class="line"><span class="ln"> 57</span><span class="cl"><span class="s2">            List of internal link dicts
</span></span></span><span class="line"><span class="ln"> 58</span><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 59</span><span class="cl">        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">use_rust</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 60</span><span class="cl">            <span class="c1"># Use optimized Rust function that parses and filters in one pass</span>
</span></span><span class="line"><span class="ln"> 61</span><span class="cl">            <span class="n">links</span> <span class="o">=</span> <span class="n">parser_rs</span><span class="o">.</span><span class="n">parse_internal_links</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 62</span><span class="cl">            <span class="k">return</span> <span class="p">[</span><span class="n">link</span><span class="o">.</span><span class="n">to_dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">links</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 63</span><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 64</span><span class="cl">            <span class="n">all_links</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_parse_python</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 65</span><span class="cl">            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filter_internal</span><span class="p">(</span><span class="n">all_links</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 66</span><span class="cl">
</span></span><span class="line"><span class="ln"> 67</span><span class="cl">    <span class="k">def</span> <span class="nf">_parse_python</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 68</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Pure Python implementation (fallback)&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 69</span><span class="cl">        <span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln"> 70</span><span class="cl">
</span></span><span class="line"><span class="ln"> 71</span><span class="cl">        <span class="n">INLINE_LINK</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;(?&lt;!!)\[([^\]]+)\]\(([^)]+)\)&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 72</span><span class="cl">        <span class="n">REFERENCE_DEF</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;(?m)^\s*\[([^\]]+)\]:\s*(.+)$&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 73</span><span class="cl">        <span class="n">REFERENCE_USE</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;\[([^\]]+)\]\[([^\]]+)\]&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 74</span><span class="cl">
</span></span><span class="line"><span class="ln"> 75</span><span class="cl">        <span class="n">links</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln"> 76</span><span class="cl">
</span></span><span class="line"><span class="ln"> 77</span><span class="cl">        <span class="c1"># Collect reference definitions</span>
</span></span><span class="line"><span class="ln"> 78</span><span class="cl">        <span class="n">reference_defs</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="ln"> 79</span><span class="cl">        <span class="k">for</span> <span class="k">match</span> <span class="ow">in</span> <span class="n">REFERENCE_DEF</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="n">content</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 80</span><span class="cl">            <span class="n">ref_name</span> <span class="o">=</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 81</span><span class="cl">            <span class="n">ref_target</span> <span class="o">=</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 82</span><span class="cl">            <span class="n">reference_defs</span><span class="p">[</span><span class="n">ref_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">ref_target</span>
</span></span><span class="line"><span class="ln"> 83</span><span class="cl">
</span></span><span class="line"><span class="ln"> 84</span><span class="cl">        <span class="c1"># Parse line by line</span>
</span></span><span class="line"><span class="ln"> 85</span><span class="cl">        <span class="n">in_code_block</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="ln"> 86</span><span class="cl">        <span class="k">for</span> <span class="n">line_num</span><span class="p">,</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">content</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">),</span> <span class="n">start</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 87</span><span class="cl">            <span class="k">if</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;```&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 88</span><span class="cl">                <span class="n">in_code_block</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">in_code_block</span>
</span></span><span class="line"><span class="ln"> 89</span><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="ln"> 90</span><span class="cl">
</span></span><span class="line"><span class="ln"> 91</span><span class="cl">            <span class="k">if</span> <span class="n">in_code_block</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 92</span><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="ln"> 93</span><span class="cl">
</span></span><span class="line"><span class="ln"> 94</span><span class="cl">            <span class="k">for</span> <span class="k">match</span> <span class="ow">in</span> <span class="n">INLINE_LINK</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="n">line</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 95</span><span class="cl">                <span class="n">links</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 96</span><span class="cl">                    <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 97</span><span class="cl">                    <span class="s2">&#34;target&#34;</span><span class="p">:</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 98</span><span class="cl">                    <span class="s2">&#34;line&#34;</span><span class="p">:</span> <span class="n">line_num</span>
</span></span><span class="line"><span class="ln"> 99</span><span class="cl">                <span class="p">})</span>
</span></span><span class="line"><span class="ln">100</span><span class="cl">
</span></span><span class="line"><span class="ln">101</span><span class="cl">            <span class="k">for</span> <span class="k">match</span> <span class="ow">in</span> <span class="n">REFERENCE_USE</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="n">line</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">102</span><span class="cl">                <span class="n">ref_name</span> <span class="o">=</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">103</span><span class="cl">                <span class="k">if</span> <span class="n">ref_name</span> <span class="ow">in</span> <span class="n">reference_defs</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">104</span><span class="cl">                    <span class="n">links</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">105</span><span class="cl">                        <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">106</span><span class="cl">                        <span class="s2">&#34;target&#34;</span><span class="p">:</span> <span class="n">reference_defs</span><span class="p">[</span><span class="n">ref_name</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">107</span><span class="cl">                        <span class="s2">&#34;line&#34;</span><span class="p">:</span> <span class="n">line_num</span>
</span></span><span class="line"><span class="ln">108</span><span class="cl">                    <span class="p">})</span>
</span></span><span class="line"><span class="ln">109</span><span class="cl">
</span></span><span class="line"><span class="ln">110</span><span class="cl">        <span class="k">return</span> <span class="n">links</span>
</span></span><span class="line"><span class="ln">111</span><span class="cl">
</span></span><span class="line"><span class="ln">112</span><span class="cl">    <span class="k">def</span> <span class="nf">_filter_internal</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">links</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">113</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Filter to internal links only&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">114</span><span class="cl">        <span class="n">external_prefixes</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">115</span><span class="cl">            <span class="s1">&#39;http://&#39;</span><span class="p">,</span> <span class="s1">&#39;https://&#39;</span><span class="p">,</span> <span class="s1">&#39;mailto:&#39;</span><span class="p">,</span> <span class="s1">&#39;tel:&#39;</span><span class="p">,</span> <span class="s1">&#39;ftp://&#39;</span>
</span></span><span class="line"><span class="ln">116</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">117</span><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">118</span><span class="cl">            <span class="n">link</span> <span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">links</span>
</span></span><span class="line"><span class="ln">119</span><span class="cl">            <span class="k">if</span> <span class="ow">not</span> <span class="n">link</span><span class="p">[</span><span class="s1">&#39;target&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;#&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">120</span><span class="cl">            <span class="ow">and</span> <span class="ow">not</span> <span class="n">link</span><span class="p">[</span><span class="s1">&#39;target&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">external_prefixes</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">121</span><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="ln">122</span><span class="cl">
</span></span><span class="line"><span class="ln">123</span><span class="cl"><span class="c1"># Convenience functions</span>
</span></span><span class="line"><span class="ln">124</span><span class="cl"><span class="k">def</span> <span class="nf">check_file</span><span class="p">(</span><span class="n">file_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">use_rust</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">125</span><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln">126</span><span class="cl"><span class="s2">    Check a single markdown file for broken links
</span></span></span><span class="line"><span class="ln">127</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">128</span><span class="cl"><span class="s2">    Args:
</span></span></span><span class="line"><span class="ln">129</span><span class="cl"><span class="s2">        file_path: Path to the markdown file
</span></span></span><span class="line"><span class="ln">130</span><span class="cl"><span class="s2">        use_rust: Whether to use Rust acceleration
</span></span></span><span class="line"><span class="ln">131</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">132</span><span class="cl"><span class="s2">    Returns:
</span></span></span><span class="line"><span class="ln">133</span><span class="cl"><span class="s2">        Dict with file_path, total_links, and internal_links count
</span></span></span><span class="line"><span class="ln">134</span><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">135</span><span class="cl">    <span class="n">checker</span> <span class="o">=</span> <span class="n">MarkdownLinkChecker</span><span class="p">(</span><span class="n">use_rust</span><span class="o">=</span><span class="n">use_rust</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">136</span><span class="cl">    <span class="n">path</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">137</span><span class="cl">    <span class="n">content</span> <span class="o">=</span> <span class="n">path</span><span class="o">.</span><span class="n">read_text</span><span class="p">(</span><span class="n">encoding</span><span class="o">=</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">138</span><span class="cl">
</span></span><span class="line"><span class="ln">139</span><span class="cl">    <span class="n">all_links</span> <span class="o">=</span> <span class="n">checker</span><span class="o">.</span><span class="n">parse_markdown_links</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">140</span><span class="cl">    <span class="n">internal_links</span> <span class="o">=</span> <span class="n">checker</span><span class="o">.</span><span class="n">parse_internal_links</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">141</span><span class="cl">
</span></span><span class="line"><span class="ln">142</span><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">143</span><span class="cl">        <span class="s2">&#34;file_path&#34;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">path</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">144</span><span class="cl">        <span class="s2">&#34;total_links&#34;</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">all_links</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">145</span><span class="cl">        <span class="s2">&#34;internal_links&#34;</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">internal_links</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">146</span><span class="cl">        <span class="s2">&#34;links&#34;</span><span class="p">:</span> <span class="n">internal_links</span>
</span></span><span class="line"><span class="ln">147</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">148</span><span class="cl">
</span></span><span class="line"><span class="ln">149</span><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">150</span><span class="cl">    <span class="c1"># Example usage</span>
</span></span><span class="line"><span class="ln">151</span><span class="cl">    <span class="n">sample</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">152</span><span class="cl">        <span class="s2">&#34;# Sample Document</span><span class="se">\n\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">153</span><span class="cl">        <span class="s2">&#34;Check the [documentation](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/docs/README.md) for more info.</span><span class="se">\n\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">154</span><span class="cl">        <span class="s2">&#34;External link: [Google](https://google.com)</span><span class="se">\n\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">155</span><span class="cl">        <span class="s2">&#34;Reference style: [API docs][api]</span><span class="se">\n\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">156</span><span class="cl">        <span class="s2">&#34;[api]: ./api/reference.md</span><span class="se">\n\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">157</span><span class="cl">        <span class="s2">&#34;~~~python</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">158</span><span class="cl">        <span class="s2">&#34;# This [link](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/should_be_ignored.md) is in a code block</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">159</span><span class="cl">        <span class="s2">&#34;~~~</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">160</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">161</span><span class="cl">
</span></span><span class="line"><span class="ln">162</span><span class="cl">    <span class="n">checker</span> <span class="o">=</span> <span class="n">MarkdownLinkChecker</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">163</span><span class="cl">    <span class="n">links</span> <span class="o">=</span> <span class="n">checker</span><span class="o">.</span><span class="n">parse_markdown_links</span><span class="p">(</span><span class="n">sample</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">164</span><span class="cl">
</span></span><span class="line"><span class="ln">165</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;All links found:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">166</span><span class="cl">    <span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">links</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">167</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;  Line </span><span class="si">{</span><span class="n">link</span><span class="p">[</span><span class="s1">&#39;line&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">: [</span><span class="si">{</span><span class="n">link</span><span class="p">[</span><span class="s1">&#39;text&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/</span><span class="si">{</span><span class="n">link</span><span class="p">[</span><span class="s1">&#39;target&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">168</span><span class="cl">
</span></span><span class="line"><span class="ln">169</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">Internal links only:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">170</span><span class="cl">    <span class="n">internal</span> <span class="o">=</span> <span class="n">checker</span><span class="o">.</span><span class="n">parse_internal_links</span><span class="p">(</span><span class="n">sample</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">171</span><span class="cl">    <span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">internal</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">172</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;  Line </span><span class="si">{</span><span class="n">link</span><span class="p">[</span><span class="s1">&#39;line&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">: [</span><span class="si">{</span><span class="n">link</span><span class="p">[</span><span class="s1">&#39;text&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/</span><span class="si">{</span><span class="n">link</span><span class="p">[</span><span class="s1">&#39;target&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">)&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="效能比較">效能比較</h3>
<p>以下是完整的效能測試腳本：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">  1</span><span class="cl"><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="s2">Performance comparison: Python vs Cython vs Rust
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="s2">This script benchmarks the three implementations on
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="s2">various markdown file sizes.
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">  7</span><span class="cl">
</span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="kn">import</span> <span class="nn">statistics</span>
</span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Tuple</span>
</span></span><span class="line"><span class="ln"> 12</span><span class="cl">
</span></span><span class="line"><span class="ln"> 13</span><span class="cl"><span class="c1"># Generate test data</span>
</span></span><span class="line"><span class="ln"> 14</span><span class="cl"><span class="k">def</span> <span class="nf">generate_markdown</span><span class="p">(</span><span class="n">num_links</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 15</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Generate markdown content with specified number of links&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 16</span><span class="cl">    <span class="n">lines</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;# Test Document</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 17</span><span class="cl">
</span></span><span class="line"><span class="ln"> 18</span><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_links</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 19</span><span class="cl">        <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 20</span><span class="cl">            <span class="c1"># Inline link</span>
</span></span><span class="line"><span class="ln"> 21</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Check [link</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/path/to/file</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">.md) for info.</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 22</span><span class="cl">        <span class="k">elif</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 23</span><span class="cl">            <span class="c1"># External link (should be filtered)</span>
</span></span><span class="line"><span class="ln"> 24</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Visit [site</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">](https://example</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">.com)</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 25</span><span class="cl">        <span class="k">elif</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 26</span><span class="cl">            <span class="c1"># Reference style link</span>
</span></span><span class="line"><span class="ln"> 27</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;See [doc</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">][ref</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">]</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 28</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;[ref</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">]: ./docs/page</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">.md</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 29</span><span class="cl">        <span class="k">elif</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 30</span><span class="cl">            <span class="c1"># Anchor link (should be filtered)</span>
</span></span><span class="line"><span class="ln"> 31</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Jump to [section</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">](#section-</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">)</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 32</span><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 33</span><span class="cl">            <span class="c1"># Regular text</span>
</span></span><span class="line"><span class="ln"> 34</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;This is paragraph </span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2"> with some text.</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 35</span><span class="cl">
</span></span><span class="line"><span class="ln"> 36</span><span class="cl">        <span class="c1"># Add occasional code blocks (using ~~~ to avoid markdown parsing issues)</span>
</span></span><span class="line"><span class="ln"> 37</span><span class="cl">        <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">20</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 38</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&#34;~~~python</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 39</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;# [fake link](/python-advanced/06-rust-extensions/case-studies/pyo3-parser/should_ignore_</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">.md)</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 40</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&#34;print(&#39;hello&#39;)</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 41</span><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&#34;~~~</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 42</span><span class="cl">
</span></span><span class="line"><span class="ln"> 43</span><span class="cl">    <span class="k">return</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 44</span><span class="cl">
</span></span><span class="line"><span class="ln"> 45</span><span class="cl"><span class="k">def</span> <span class="nf">benchmark</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 46</span><span class="cl">    <span class="n">func</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="nb">str</span><span class="p">],</span> <span class="n">List</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 47</span><span class="cl">    <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 48</span><span class="cl">    <span class="n">iterations</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">100</span>
</span></span><span class="line"><span class="ln"> 49</span><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 50</span><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="s2">    Benchmark a function
</span></span></span><span class="line"><span class="ln"> 52</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="s2">    Returns:
</span></span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="s2">        Tuple of (mean_time_ms, min_time_ms, max_time_ms)
</span></span></span><span class="line"><span class="ln"> 55</span><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 56</span><span class="cl">    <span class="n">times</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln"> 57</span><span class="cl">
</span></span><span class="line"><span class="ln"> 58</span><span class="cl">    <span class="c1"># Warmup</span>
</span></span><span class="line"><span class="ln"> 59</span><span class="cl">    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 60</span><span class="cl">        <span class="n">func</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 61</span><span class="cl">
</span></span><span class="line"><span class="ln"> 62</span><span class="cl">    <span class="c1"># Actual benchmark</span>
</span></span><span class="line"><span class="ln"> 63</span><span class="cl">    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">iterations</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 64</span><span class="cl">        <span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 65</span><span class="cl">        <span class="n">func</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 66</span><span class="cl">        <span class="n">end</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 67</span><span class="cl">        <span class="n">times</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">)</span>  <span class="c1"># Convert to ms</span>
</span></span><span class="line"><span class="ln"> 68</span><span class="cl">
</span></span><span class="line"><span class="ln"> 69</span><span class="cl">    <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 70</span><span class="cl">        <span class="n">statistics</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">times</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 71</span><span class="cl">        <span class="nb">min</span><span class="p">(</span><span class="n">times</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 72</span><span class="cl">        <span class="nb">max</span><span class="p">(</span><span class="n">times</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 73</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln"> 74</span><span class="cl">
</span></span><span class="line"><span class="ln"> 75</span><span class="cl"><span class="k">def</span> <span class="nf">run_benchmarks</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 76</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Run benchmarks comparing all implementations&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 77</span><span class="cl">
</span></span><span class="line"><span class="ln"> 78</span><span class="cl">    <span class="c1"># Import implementations</span>
</span></span><span class="line"><span class="ln"> 79</span><span class="cl">    <span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln"> 80</span><span class="cl">
</span></span><span class="line"><span class="ln"> 81</span><span class="cl">    <span class="c1"># Pure Python implementation</span>
</span></span><span class="line"><span class="ln"> 82</span><span class="cl">    <span class="n">INLINE_LINK</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;(?&lt;!!)\[([^\]]+)\]\(([^)]+)\)&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 83</span><span class="cl">
</span></span><span class="line"><span class="ln"> 84</span><span class="cl">    <span class="k">def</span> <span class="nf">parse_python</span><span class="p">(</span><span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 85</span><span class="cl">        <span class="n">links</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln"> 86</span><span class="cl">        <span class="n">in_code_block</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="ln"> 87</span><span class="cl">        <span class="k">for</span> <span class="n">line_num</span><span class="p">,</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">content</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">),</span> <span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 88</span><span class="cl">            <span class="k">if</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;```&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 89</span><span class="cl">                <span class="n">in_code_block</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">in_code_block</span>
</span></span><span class="line"><span class="ln"> 90</span><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="ln"> 91</span><span class="cl">            <span class="k">if</span> <span class="n">in_code_block</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 92</span><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="ln"> 93</span><span class="cl">            <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">INLINE_LINK</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="n">line</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 94</span><span class="cl">                <span class="n">links</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="s2">&#34;target&#34;</span><span class="p">:</span> <span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="s2">&#34;line&#34;</span><span class="p">:</span> <span class="n">line_num</span><span class="p">})</span>
</span></span><span class="line"><span class="ln"> 95</span><span class="cl">        <span class="k">return</span> <span class="n">links</span>
</span></span><span class="line"><span class="ln"> 96</span><span class="cl">
</span></span><span class="line"><span class="ln"> 97</span><span class="cl">    <span class="c1"># Try to import Rust implementation</span>
</span></span><span class="line"><span class="ln"> 98</span><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 99</span><span class="cl">        <span class="kn">import</span> <span class="nn">markdown_parser_rs</span> <span class="k">as</span> <span class="nn">rust_parser</span>
</span></span><span class="line"><span class="ln">100</span><span class="cl">        <span class="n">has_rust</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="ln">101</span><span class="cl">    <span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">102</span><span class="cl">        <span class="n">has_rust</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="ln">103</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Rust module not available&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">104</span><span class="cl">
</span></span><span class="line"><span class="ln">105</span><span class="cl">    <span class="c1"># Test sizes</span>
</span></span><span class="line"><span class="ln">106</span><span class="cl">    <span class="n">sizes</span> <span class="o">=</span> <span class="p">[</span><span class="mi">100</span><span class="p">,</span> <span class="mi">500</span><span class="p">,</span> <span class="mi">1000</span><span class="p">,</span> <span class="mi">5000</span><span class="p">,</span> <span class="mi">10000</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">107</span><span class="cl">
</span></span><span class="line"><span class="ln">108</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">70</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">109</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Markdown Link Parser Benchmark&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">110</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">70</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">111</span><span class="cl">    <span class="nb">print</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">112</span><span class="cl">
</span></span><span class="line"><span class="ln">113</span><span class="cl">    <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">114</span><span class="cl">
</span></span><span class="line"><span class="ln">115</span><span class="cl">    <span class="k">for</span> <span class="n">size</span> <span class="ow">in</span> <span class="n">sizes</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">116</span><span class="cl">        <span class="n">content</span> <span class="o">=</span> <span class="n">generate_markdown</span><span class="p">(</span><span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">117</span><span class="cl">        <span class="n">content_kb</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">content</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">))</span> <span class="o">/</span> <span class="mi">1024</span>
</span></span><span class="line"><span class="ln">118</span><span class="cl">
</span></span><span class="line"><span class="ln">119</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Test: </span><span class="si">{</span><span class="n">size</span><span class="si">}</span><span class="s2"> links (~</span><span class="si">{</span><span class="n">content_kb</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2"> KB)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">120</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;-&#34;</span> <span class="o">*</span> <span class="mi">50</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">121</span><span class="cl">
</span></span><span class="line"><span class="ln">122</span><span class="cl">        <span class="c1"># Python benchmark</span>
</span></span><span class="line"><span class="ln">123</span><span class="cl">        <span class="n">py_mean</span><span class="p">,</span> <span class="n">py_min</span><span class="p">,</span> <span class="n">py_max</span> <span class="o">=</span> <span class="n">benchmark</span><span class="p">(</span><span class="n">parse_python</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">124</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;  Python:  </span><span class="si">{</span><span class="n">py_mean</span><span class="si">:</span><span class="s2">8.3f</span><span class="si">}</span><span class="s2"> ms (min: </span><span class="si">{</span><span class="n">py_min</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">, max: </span><span class="si">{</span><span class="n">py_max</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">125</span><span class="cl">
</span></span><span class="line"><span class="ln">126</span><span class="cl">        <span class="c1"># Rust benchmark</span>
</span></span><span class="line"><span class="ln">127</span><span class="cl">        <span class="k">if</span> <span class="n">has_rust</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">128</span><span class="cl">            <span class="n">rs_mean</span><span class="p">,</span> <span class="n">rs_min</span><span class="p">,</span> <span class="n">rs_max</span> <span class="o">=</span> <span class="n">benchmark</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">129</span><span class="cl">                <span class="n">rust_parser</span><span class="o">.</span><span class="n">parse_markdown_links</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">130</span><span class="cl">                <span class="n">content</span>
</span></span><span class="line"><span class="ln">131</span><span class="cl">            <span class="p">)</span>
</span></span><span class="line"><span class="ln">132</span><span class="cl">            <span class="n">speedup</span> <span class="o">=</span> <span class="n">py_mean</span> <span class="o">/</span> <span class="n">rs_mean</span>
</span></span><span class="line"><span class="ln">133</span><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;  Rust:    </span><span class="si">{</span><span class="n">rs_mean</span><span class="si">:</span><span class="s2">8.3f</span><span class="si">}</span><span class="s2"> ms (min: </span><span class="si">{</span><span class="n">rs_min</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">, max: </span><span class="si">{</span><span class="n">rs_max</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">134</span><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;  Speedup: </span><span class="si">{</span><span class="n">speedup</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2">x faster&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">135</span><span class="cl">
</span></span><span class="line"><span class="ln">136</span><span class="cl">        <span class="nb">print</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">137</span><span class="cl">        <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">138</span><span class="cl">            <span class="s2">&#34;size&#34;</span><span class="p">:</span> <span class="n">size</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">139</span><span class="cl">            <span class="s2">&#34;python_ms&#34;</span><span class="p">:</span> <span class="n">py_mean</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">140</span><span class="cl">            <span class="s2">&#34;rust_ms&#34;</span><span class="p">:</span> <span class="n">rs_mean</span> <span class="k">if</span> <span class="n">has_rust</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">141</span><span class="cl">            <span class="s2">&#34;speedup&#34;</span><span class="p">:</span> <span class="n">speedup</span> <span class="k">if</span> <span class="n">has_rust</span> <span class="k">else</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">142</span><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="ln">143</span><span class="cl">
</span></span><span class="line"><span class="ln">144</span><span class="cl">    <span class="c1"># Summary table</span>
</span></span><span class="line"><span class="ln">145</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">70</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">146</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Summary&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">147</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">70</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">148</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="s1">&#39;Links&#39;</span><span class="si">:</span><span class="s2">&lt;10</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="s1">&#39;Python (ms)&#39;</span><span class="si">:</span><span class="s2">&lt;15</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="s1">&#39;Rust (ms)&#39;</span><span class="si">:</span><span class="s2">&lt;15</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="s1">&#39;Speedup&#39;</span><span class="si">:</span><span class="s2">&lt;10</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">149</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;-&#34;</span> <span class="o">*</span> <span class="mi">50</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">150</span><span class="cl">    <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">151</span><span class="cl">        <span class="n">rust_str</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s1">&#39;rust_ms&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">&#34;</span> <span class="k">if</span> <span class="n">r</span><span class="p">[</span><span class="s1">&#39;rust_ms&#39;</span><span class="p">]</span> <span class="k">else</span> <span class="s2">&#34;N/A&#34;</span>
</span></span><span class="line"><span class="ln">152</span><span class="cl">        <span class="n">speedup_str</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s1">&#39;speedup&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2">x&#34;</span> <span class="k">if</span> <span class="n">r</span><span class="p">[</span><span class="s1">&#39;speedup&#39;</span><span class="p">]</span> <span class="k">else</span> <span class="s2">&#34;N/A&#34;</span>
</span></span><span class="line"><span class="ln">153</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s1">&#39;size&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">&lt;10</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s1">&#39;python_ms&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">&lt;15.3f</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">rust_str</span><span class="si">:</span><span class="s2">&lt;15</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">speedup_str</span><span class="si">:</span><span class="s2">&lt;10</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">154</span><span class="cl">
</span></span><span class="line"><span class="ln">155</span><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">156</span><span class="cl">    <span class="n">run_benchmarks</span><span class="p">()</span></span></span></code></pre></div><p><strong>典型效能結果</strong>：</p>
<table>
  <thead>
      <tr>
          <th>連結數</th>
          <th>Python (ms)</th>
          <th>Rust (ms)</th>
          <th>加速比</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>100</td>
          <td>0.45</td>
          <td>0.03</td>
          <td>15x</td>
      </tr>
      <tr>
          <td>500</td>
          <td>2.10</td>
          <td>0.12</td>
          <td>18x</td>
      </tr>
      <tr>
          <td>1000</td>
          <td>4.25</td>
          <td>0.22</td>
          <td>19x</td>
      </tr>
      <tr>
          <td>5000</td>
          <td>21.50</td>
          <td>1.05</td>
          <td>20x</td>
      </tr>
      <tr>
          <td>10000</td>
          <td>43.80</td>
          <td>2.10</td>
          <td>21x</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>注意：實際效能取決於硬體和內容複雜度。Rust 的優勢在大型檔案上更加明顯。</p></blockquote>
<h2 id="設計權衡">設計權衡</h2>
<table>
  <thead>
      <tr>
          <th>面向</th>
          <th>Python</th>
          <th>Cython</th>
          <th>Rust (PyO3)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>開發速度</td>
          <td>快（數小時）</td>
          <td>中（數天）</td>
          <td>慢（數天至週）</td>
      </tr>
      <tr>
          <td>執行速度</td>
          <td>1x</td>
          <td>2-10x</td>
          <td>10-100x</td>
      </tr>
      <tr>
          <td>記憶體安全</td>
          <td>GC 管理</td>
          <td>GC 管理</td>
          <td>編譯時保證</td>
      </tr>
      <tr>
          <td>學習曲線</td>
          <td>低</td>
          <td>中</td>
          <td>高</td>
      </tr>
      <tr>
          <td>除錯難度</td>
          <td>低</td>
          <td>中</td>
          <td>高</td>
      </tr>
      <tr>
          <td>部署複雜度</td>
          <td>低</td>
          <td>中</td>
          <td>中</td>
      </tr>
      <tr>
          <td>跨平台支援</td>
          <td>優秀</td>
          <td>需編譯</td>
          <td>需編譯</td>
      </tr>
      <tr>
          <td>生態系統</td>
          <td>豐富</td>
          <td>有限</td>
          <td>豐富（Cargo）</td>
      </tr>
  </tbody>
</table>
<h3 id="選擇決策樹">選擇決策樹</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">需要加速 Python 程式碼？
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── 否 → 保持純 Python
</span></span><span class="line"><span class="ln">3</span><span class="cl">└── 是 → 效能需求多高？
</span></span><span class="line"><span class="ln">4</span><span class="cl">    ├── 2-5x 足夠 → 考慮 Cython
</span></span><span class="line"><span class="ln">5</span><span class="cl">    └── 需要 10x+ → 團隊有 Rust 經驗？
</span></span><span class="line"><span class="ln">6</span><span class="cl">        ├── 是 → 使用 PyO3
</span></span><span class="line"><span class="ln">7</span><span class="cl">        └── 否 → 效能瓶頸明確嗎？
</span></span><span class="line"><span class="ln">8</span><span class="cl">            ├── 是 → 值得學習 Rust
</span></span><span class="line"><span class="ln">9</span><span class="cl">            └── 否 → 先用 Cython，後續再評估</span></span></code></pre></div><h2 id="什麼時候該用-rust">什麼時候該用 Rust？</h2>
<p><strong>適合使用</strong>：</p>
<ul>
<li>需要極致效能（10x+ 加速）</li>
<li>CPU 密集的核心邏輯</li>
<li>需要處理大量資料</li>
<li>團隊有 Rust 經驗</li>
<li>需要記憶體安全保證</li>
<li>可利用 Rust 生態系統（如 regex, rayon）</li>
</ul>
<p><strong>不建議使用</strong>：</p>
<ul>
<li>效能需求不高</li>
<li>快速原型開發</li>
<li>團隊不熟悉 Rust</li>
<li>專案生命週期短</li>
<li>I/O 密集型任務（瓶頸不在 CPU）</li>
</ul>
<h2 id="練習">練習</h2>
<h3 id="練習-1基礎練習---字串處理函式">練習 1：基礎練習 - 字串處理函式</h3>
<p>用 PyO3 實作一個字串處理函式，將 Markdown 標題轉換為 slug：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 目標：將 &#34;Hello World! 你好&#34; 轉換為 &#34;hello-world-你好&#34;
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">slugify</span><span class="p">(</span><span class="n">title</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">    </span><span class="c1">// 你的實作
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="fm">todo!</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><p><strong>提示</strong>：</p>
<ul>
<li>轉換為小寫</li>
<li>移除特殊字元</li>
<li>用連字號替換空白</li>
</ul>
<p><strong>參考解答</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">slugify</span><span class="p">(</span><span class="n">title</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="n">title</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">chars</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">c</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">is_alphanumeric</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">                </span><span class="n">c</span><span class="p">.</span><span class="n">to_lowercase</span><span class="p">().</span><span class="n">next</span><span class="p">().</span><span class="n">unwrap_or</span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">is_whitespace</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">                </span><span class="sc">&#39;-&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">                </span><span class="c1">// Keep non-ASCII chars (like CJK)
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="w">                </span><span class="k">if</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">is_ascii</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="sc">&#39;\0&#39;</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|&amp;</span><span class="n">c</span><span class="o">|</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">&#39;\0&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">        </span><span class="c1">// Clean up multiple consecutive dashes
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sc">&#39;-&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="o">!</span><span class="n">s</span><span class="p">.</span><span class="n">is_empty</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;&gt;</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="s">&#34;-&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="練習-2進階練習---模式匹配">練習 2：進階練習 - 模式匹配</h3>
<p>用 regex crate 實作一個函式，提取 Markdown 文件中的所有標題：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// 目標：提取 # 標題，## 標題，### 標題 等
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Heading</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="n">level</span>: <span class="kt">usize</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="n">text</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="n">line</span>: <span class="kt">usize</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">extract_headings</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Heading</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span><span class="c1">// 你的實作
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="fm">todo!</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><p><strong>提示</strong>：</p>
<ul>
<li>使用 <code>^#{1,6}\s+(.+)$</code> 正則表達式</li>
<li>記得處理 multiline 模式</li>
</ul>
<p><strong>參考解答</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">once_cell</span>::<span class="n">sync</span>::<span class="n">Lazy</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">regex</span>::<span class="n">Regex</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">HEADING_PATTERN</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;(?m)^(#{1,6})\s+(.+)$&#34;</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">extract_headings</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Heading</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">headings</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">current_line</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">last_end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">cap</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="no">HEADING_PATTERN</span><span class="p">.</span><span class="n">captures_iter</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">match_start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="n">unwrap</span><span class="p">().</span><span class="n">start</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">        </span><span class="c1">// Count newlines to determine line number
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="n">current_line</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">content</span><span class="p">[</span><span class="n">last_end</span><span class="o">..</span><span class="n">match_start</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">chars</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|&amp;</span><span class="n">c</span><span class="o">|</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="sc">&#39;\n&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">count</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">        </span><span class="n">last_end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">match_start</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">level</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">len</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">text</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cap</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">trim</span><span class="p">().</span><span class="n">to_string</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">        </span><span class="n">headings</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">Heading</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">            </span><span class="n">level</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">            </span><span class="n">text</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">            </span><span class="n">line</span>: <span class="nc">current_line</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">    </span><span class="n">headings</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="練習-3挑戰題---串流解析">練習 3：挑戰題 - 串流解析</h3>
<p>實作一個可處理大型檔案的串流解析器：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="n">BufRead</span><span class="p">,</span><span class="w"> </span><span class="n">BufReader</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">File</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">StreamingParser</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="c1">// 你的實作
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">StreamingParser</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">file_path</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">        </span><span class="c1">// 開啟檔案
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="fm">todo!</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="sd">/// 迭代器協議
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__iter__</span><span class="p">(</span><span class="n">slf</span>: <span class="nc">PyRef</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyRef</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">        </span><span class="n">slf</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__next__</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="c1">// 讀取下一個連結
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="fm">todo!</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><p><strong>提示</strong>：</p>
<ul>
<li>使用 <code>BufReader</code> 逐行讀取</li>
<li>維護狀態（行號、程式碼區塊）</li>
<li>實作 Python 迭代器協議</li>
</ul>
<p><strong>參考解答思路</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">File</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="n">BufRead</span><span class="p">,</span><span class="w"> </span><span class="n">BufReader</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">StreamingParser</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="n">reader</span>: <span class="nc">BufReader</span><span class="o">&lt;</span><span class="n">File</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="n">line_number</span>: <span class="kt">usize</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="n">in_code_block</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="c1">// Buffer for pending links found on current line
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">pending_links</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">StreamingParser</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">file_path</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">File</span>::<span class="n">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map_err</span><span class="p">(</span><span class="o">|</span><span class="n">e</span><span class="o">|</span><span class="w"> </span><span class="n">PyErr</span>::<span class="n">new</span>::<span class="o">&lt;</span><span class="n">pyo3</span>::<span class="n">exceptions</span>::<span class="n">PyIOError</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="o">&gt;</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">                </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;Cannot open file: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">            </span><span class="p">))</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">StreamingParser</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">            </span><span class="n">reader</span>: <span class="nc">BufReader</span>::<span class="n">new</span><span class="p">(</span><span class="n">file</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">            </span><span class="n">line_number</span>: <span class="mi">0</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">            </span><span class="n">in_code_block</span>: <span class="nc">false</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">            </span><span class="n">pending_links</span>: <span class="nb">Vec</span>::<span class="n">new</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__iter__</span><span class="p">(</span><span class="n">slf</span>: <span class="nc">PyRef</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyRef</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">        </span><span class="n">slf</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__next__</span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">slf</span>: <span class="nc">PyRefMut</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">        </span><span class="c1">// Return pending links first
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">link</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">slf</span><span class="p">.</span><span class="n">pending_links</span><span class="p">.</span><span class="n">pop</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">link</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">        </span><span class="c1">// Read and parse lines until we find links
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">        </span><span class="k">loop</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">            </span><span class="n">line</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">            </span><span class="k">match</span><span class="w"> </span><span class="n">slf</span><span class="p">.</span><span class="n">reader</span><span class="p">.</span><span class="n">read_line</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">line</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">                </span><span class="nb">Ok</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">None</span><span class="p">,</span><span class="w"> </span><span class="c1">// EOF
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="c1"></span><span class="w">                </span><span class="nb">Ok</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">                    </span><span class="n">slf</span><span class="p">.</span><span class="n">line_number</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">                    </span><span class="c1">// Handle code blocks
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="c1"></span><span class="w">                    </span><span class="k">if</span><span class="w"> </span><span class="n">line</span><span class="p">.</span><span class="n">trim_start</span><span class="p">().</span><span class="n">starts_with</span><span class="p">(</span><span class="s">&#34;```&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">                        </span><span class="n">slf</span><span class="p">.</span><span class="n">in_code_block</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">!</span><span class="n">slf</span><span class="p">.</span><span class="n">in_code_block</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">                        </span><span class="k">continue</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w">                    </span><span class="k">if</span><span class="w"> </span><span class="n">slf</span><span class="p">.</span><span class="n">in_code_block</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="w">                        </span><span class="k">continue</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="w">                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="w">                    </span><span class="c1">// Parse links from this line
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="c1"></span><span class="w">                    </span><span class="kd">let</span><span class="w"> </span><span class="n">links</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parse_line_links</span><span class="p">(</span><span class="o">&amp;</span><span class="n">line</span><span class="p">,</span><span class="w"> </span><span class="n">slf</span><span class="p">.</span><span class="n">line_number</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="w">                    </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="n">links</span><span class="p">.</span><span class="n">is_empty</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="w">                        </span><span class="n">slf</span><span class="p">.</span><span class="n">pending_links</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">links</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="w">                        </span><span class="k">return</span><span class="w"> </span><span class="n">slf</span><span class="p">.</span><span class="n">pending_links</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">65</span><span class="cl"><span class="w">                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">67</span><span class="cl"><span class="w">                </span><span class="nb">Err</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">None</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">69</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">71</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">72</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">73</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parse_line_links</span><span class="p">(</span><span class="n">line</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">line_number</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">PyMarkdownLink</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">74</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">links</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">75</span><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">cap</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="no">INLINE_LINK_PATTERN</span><span class="p">.</span><span class="n">captures_iter</span><span class="p">(</span><span class="n">line</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">76</span><span class="cl"><span class="w">        </span><span class="n">links</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">PyMarkdownLink</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">77</span><span class="cl"><span class="w">            </span><span class="n">text</span>: <span class="nc">cap</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">78</span><span class="cl"><span class="w">            </span><span class="n">target</span>: <span class="nc">cap</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">79</span><span class="cl"><span class="w">            </span><span class="n">line</span>: <span class="nc">line_number</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">80</span><span class="cl"><span class="w">        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">81</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">82</span><span class="cl"><span class="w">    </span><span class="n">links</span><span class="w">
</span></span></span><span class="line"><span class="ln">83</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://pyo3.rs/">PyO3 官方文件</a>：完整的 PyO3 指南</li>
<li><a href="https://www.maturin.rs/">Maturin 官方文件</a>：Rust Python 套件建置工具</li>
<li><a href="https://docs.rs/regex/">Rust regex crate</a>：高效能正則表達式</li>
<li><a href="https://pyo3.rs/v0.22.0/guide">PyO3 使用者指南</a>：進階用法</li>
<li><a href="https://doc.rust-lang.org/book/">Rust 程式設計語言</a>：官方 Rust 教學</li>
</ul>
<hr>
<p>下一章：<a href="/blog/python-advanced/06-rust-extensions/case-studies/rust-regex/" data-link-title="案例：Rust 正則表達式" data-link-desc="用 Rust regex crate 加速 Hook 驗證器的模式匹配">Rust 正則表達式</a></p>
]]></content:encoded></item><item><title>5.1 為什麼選擇 Rust？</title><link>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/why-rust/</link><pubDate>Tue, 20 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/why-rust/</guid><description>&lt;p>本章比較 Rust 與傳統 C/C++ 作為 Python 擴展語言的優缺點。&lt;/p>
&lt;h2 id="本章目標">本章目標&lt;/h2>
&lt;p>學完本章後，你將能夠：&lt;/p>
&lt;ol>
&lt;li>理解 Rust 的記憶體安全保證&lt;/li>
&lt;li>評估 Rust vs C/C++ 的取捨&lt;/li>
&lt;li>認識使用 Rust 的知名 Python 專案&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="原理層rust-的核心優勢">【原理層】Rust 的核心優勢&lt;/h2>
&lt;h3 id="記憶體安全">記憶體安全&lt;/h3>
&lt;p>Rust 透過所有權（Ownership）系統在編譯時保證記憶體安全：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">// Rust 的所有權規則
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">String&lt;/span>::&lt;span class="n">from&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;hello&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s1&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// s1 的所有權轉移給 s2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// println!(&amp;#34;{}&amp;#34;, s1); // 編譯錯誤！s1 已經無效
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// OK
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 借用（Borrowing）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">calculate_length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="kt">usize&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// s 離開作用域，但不會釋放記憶體（只是借用）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">String&lt;/span>::&lt;span class="n">from&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;hello&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">calculate_length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 借用 s
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;長度: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">, 字串: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// s 仍然有效
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>與 C/C++ 的對比：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">// C 語言：常見的記憶體錯誤
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="c1">// 1. Use After Free
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">malloc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="nf">free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ptr&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;%s&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 未定義行為！
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1">// 2. Double Free
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">malloc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nf">free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ptr&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nf">free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ptr&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 未定義行為！
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1">// 3. Buffer Overflow
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">char&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="nf">strcpy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;This string is way too long!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 溢位！
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="c1">// 4. Null Pointer Dereference
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;%c&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">ptr&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Crash!
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">// Rust：上述錯誤在編譯時就會被捕捉
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 1. Use After Free - 不可能
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">String&lt;/span>::&lt;span class="n">from&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;hello&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nb">drop&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 明確釋放
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1">// println!(&amp;#34;{}&amp;#34;, s); // 編譯錯誤：value borrowed after move
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 2. Double Free - 不可能
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1">// 所有權系統確保每個值只會被釋放一次
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 3. Buffer Overflow - 執行時檢查
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">vec!&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">];&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// v[10]; // 執行時 panic，不是未定義行為
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 4. Null Pointer - 使用 Option 類型
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">maybe_value&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">i32&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">None&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 必須明確處理 None 的情況
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">match&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">maybe_value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;值: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">None&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;沒有值&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="並行安全">並行安全&lt;/h3>
&lt;p>Rust 的類型系統在編譯時防止資料競爭：&lt;/p></description><content:encoded><![CDATA[<p>本章比較 Rust 與傳統 C/C++ 作為 Python 擴展語言的優缺點。</p>
<h2 id="本章目標">本章目標</h2>
<p>學完本章後，你將能夠：</p>
<ol>
<li>理解 Rust 的記憶體安全保證</li>
<li>評估 Rust vs C/C++ 的取捨</li>
<li>認識使用 Rust 的知名 Python 專案</li>
</ol>
<hr>
<h2 id="原理層rust-的核心優勢">【原理層】Rust 的核心優勢</h2>
<h3 id="記憶體安全">記憶體安全</h3>
<p>Rust 透過所有權（Ownership）系統在編譯時保證記憶體安全：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// Rust 的所有權規則
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">s1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">from</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">s2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s1</span><span class="p">;</span><span class="w">  </span><span class="c1">// s1 的所有權轉移給 s2
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="c1">// println!(&#34;{}&#34;, s1);  // 編譯錯誤！s1 已經無效
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;</span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">s2</span><span class="p">);</span><span class="w">     </span><span class="c1">// OK
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="c1">// 借用（Borrowing）
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">calculate_length</span><span class="p">(</span><span class="n">s</span>: <span class="kp">&amp;</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="n">s</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">  </span><span class="c1">// s 離開作用域，但不會釋放記憶體（只是借用）
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">from</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">calculate_length</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="p">);</span><span class="w">  </span><span class="c1">// 借用 s
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;長度: </span><span class="si">{}</span><span class="s">, 字串: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">);</span><span class="w">  </span><span class="c1">// s 仍然有效
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div><p>與 C/C++ 的對比：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// C 語言：常見的記憶體錯誤
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1">// 1. Use After Free
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span><span class="kt">char</span><span class="o">*</span> <span class="n">ptr</span> <span class="o">=</span> <span class="nf">malloc</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="nf">free</span><span class="p">(</span><span class="n">ptr</span><span class="p">);</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%s&#34;</span><span class="p">,</span> <span class="n">ptr</span><span class="p">);</span>  <span class="c1">// 未定義行為！
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1">// 2. Double Free
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"></span><span class="kt">char</span><span class="o">*</span> <span class="n">ptr</span> <span class="o">=</span> <span class="nf">malloc</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nf">free</span><span class="p">(</span><span class="n">ptr</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nf">free</span><span class="p">(</span><span class="n">ptr</span><span class="p">);</span>  <span class="c1">// 未定義行為！
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1">// 3. Buffer Overflow
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nf">strcpy</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="s">&#34;This string is way too long!&#34;</span><span class="p">);</span>  <span class="c1">// 溢位！
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c1">// 4. Null Pointer Dereference
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span><span class="kt">char</span><span class="o">*</span> <span class="n">ptr</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%c&#34;</span><span class="p">,</span> <span class="o">*</span><span class="n">ptr</span><span class="p">);</span>  <span class="c1">// Crash!
</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// Rust：上述錯誤在編譯時就會被捕捉
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="c1">// 1. Use After Free - 不可能
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span><span class="kd">let</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">from</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="nb">drop</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w">  </span><span class="c1">// 明確釋放
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1">// println!(&#34;{}&#34;, s);  // 編譯錯誤：value borrowed after move
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="c1">// 2. Double Free - 不可能
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1">// 所有權系統確保每個值只會被釋放一次
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="c1">// 3. Buffer Overflow - 執行時檢查
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">];</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w"></span><span class="c1">// v[10];  // 執行時 panic，不是未定義行為
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="c1">// 4. Null Pointer - 使用 Option 類型
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"></span><span class="kd">let</span><span class="w"> </span><span class="n">maybe_value</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">None</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="c1">// 必須明確處理 None 的情況
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span><span class="k">match</span><span class="w"> </span><span class="n">maybe_value</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">    </span><span class="nb">Some</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;值: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="nb">None</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;沒有值&#34;</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="並行安全">並行安全</h3>
<p>Rust 的類型系統在編譯時防止資料競爭：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">thread</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="c1">// 編譯錯誤：不能在多個執行緒中修改同一資料
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">wont_compile</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">];</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="n">thread</span>::<span class="n">spawn</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">        </span><span class="n">data</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span><span class="w">  </span><span class="c1">// 錯誤：無法借用
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="n">data</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span><span class="c1">// 正確：使用 Arc 和 Mutex
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">sync</span>::<span class="p">{</span><span class="n">Arc</span><span class="p">,</span><span class="w"> </span><span class="n">Mutex</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">correct_approach</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">new</span><span class="p">(</span><span class="n">Mutex</span>::<span class="n">new</span><span class="p">(</span><span class="fm">vec!</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">]));</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">data_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">clone</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">thread</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data_clone</span><span class="p">.</span><span class="n">lock</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="n">d</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">lock</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="n">d</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">    </span><span class="n">handle</span><span class="p">.</span><span class="n">join</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="零成本抽象">零成本抽象</h3>
<p>高階語法不會帶來執行時開銷：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 迭代器鏈式操作
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="kd">let</span><span class="w"> </span><span class="n">sum</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">1000</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">sum</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="w"></span><span class="c1">// 編譯後等同於手寫的迴圈
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="c1">// 沒有額外的函式呼叫或記憶體分配
</span></span></span></code></pre></div><hr>
<h2 id="比較rust-vs-cc">【比較】Rust vs C/C++</h2>
<h3 id="效能比較">效能比較</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">效能特性比較：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">                    Rust        C           C++
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">────────────────────────────────────────────────────
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">執行速度            5/5         5/5         5/5
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">編譯時間            2/5         4/5         3/5
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">二進位大小          3/5         5/5         4/5
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">記憶體使用          5/5         5/5         4/5
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">說明：
</span></span><span class="line"><span class="ln">11</span><span class="cl">- 執行速度三者相當（都編譯為原生機器碼）
</span></span><span class="line"><span class="ln">12</span><span class="cl">- Rust 編譯時間較長（複雜的類型檢查）
</span></span><span class="line"><span class="ln">13</span><span class="cl">- Rust 二進位可能較大（標準庫靜態連結）</span></span></code></pre></div><h3 id="開發體驗比較">開發體驗比較</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">開發體驗：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">                    Rust        C           C++
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">────────────────────────────────────────────────────
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">學習曲線            陡峭        中等         陡峭
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">除錯難度            較易        困難         困難
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">錯誤訊息            優秀        普通         差
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">套件管理 (Cargo)    5/5         無           2/5
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">IDE 支援            4/5         5/5         5/5
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">說明：
</span></span><span class="line"><span class="ln">12</span><span class="cl">- Rust 的學習曲線主要來自所有權系統
</span></span><span class="line"><span class="ln">13</span><span class="cl">- Rust 的錯誤通常在編譯時發現，更容易修復
</span></span><span class="line"><span class="ln">14</span><span class="cl">- Cargo 提供了優秀的套件管理和建構系統</span></span></code></pre></div><h3 id="安全性比較">安全性比較</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">安全性：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">問題類型              Rust                C/C++
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">──────────────────────────────────────────────────────
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">記憶體洩漏            可能（較少見）      常見
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Use After Free        編譯時防止          常見
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">Buffer Overflow       執行時 panic        未定義行為
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">Null Pointer          使用 Option         常見 crash
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">Data Race             編譯時防止          常見
</span></span><span class="line"><span class="ln">10</span><span class="cl">未初始化變數          編譯時防止          可能
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">Rust 的 unsafe：
</span></span><span class="line"><span class="ln">13</span><span class="cl">- 可以繞過某些安全檢查
</span></span><span class="line"><span class="ln">14</span><span class="cl">- 明確標記，易於審查
</span></span><span class="line"><span class="ln">15</span><span class="cl">- 應該盡量減少使用</span></span></code></pre></div><hr>
<h2 id="案例使用-rust-的知名-python-專案">【案例】使用 Rust 的知名 Python 專案</h2>
<h3 id="tiktokenopenai">tiktoken（OpenAI）</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">tiktoken - OpenAI 的 tokenizer
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">用途：
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">- GPT 模型的 token 編碼/解碼
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">- 處理大量文字資料
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">為什麼選擇 Rust：
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">- 效能要求高（處理大量請求）
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">- 需要處理各種邊界情況
</span></span><span class="line"><span class="ln">10</span><span class="cl">- 記憶體安全很重要
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">效能數據：
</span></span><span class="line"><span class="ln">13</span><span class="cl">- 比純 Python 實現快 3-10x
</span></span><span class="line"><span class="ln">14</span><span class="cl">- 與 C++ 實現效能相當</span></span></code></pre></div><h3 id="tokenizershugging-face">tokenizers（Hugging Face）</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">tokenizers - Hugging Face 的 tokenizer 函式庫
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">用途：
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">- NLP 模型的 token 處理
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">- 支援多種 tokenization 演算法
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">特點：
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">- 純 Rust 核心
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">- PyO3 提供 Python 綁定
</span></span><span class="line"><span class="ln">10</span><span class="cl">- 支援多種語言綁定（Node.js、Ruby 等）
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">為什麼選擇 Rust：
</span></span><span class="line"><span class="ln">13</span><span class="cl">- 需要高效能的字串處理
</span></span><span class="line"><span class="ln">14</span><span class="cl">- 需要安全地處理任意輸入
</span></span><span class="line"><span class="ln">15</span><span class="cl">- 跨平台支援</span></span></code></pre></div><h3 id="polars">Polars</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Polars - 高效能 DataFrame 函式庫
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">用途：
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">- pandas 的替代方案
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">- 大規模資料處理
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">特點：
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">- 比 pandas 快 10-100x（某些操作）
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">- 惰性求值
</span></span><span class="line"><span class="ln">10</span><span class="cl">- 多執行緒
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">為什麼選擇 Rust：
</span></span><span class="line"><span class="ln">13</span><span class="cl">- 需要最佳效能
</span></span><span class="line"><span class="ln">14</span><span class="cl">- 需要安全的並行處理
</span></span><span class="line"><span class="ln">15</span><span class="cl">- Arrow 生態系統整合
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">使用範例：
</span></span><span class="line"><span class="ln">18</span><span class="cl">import polars as pl
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl">df = pl.read_csv(&#34;large_file.csv&#34;)
</span></span><span class="line"><span class="ln">21</span><span class="cl">result = (
</span></span><span class="line"><span class="ln">22</span><span class="cl">    df.lazy()
</span></span><span class="line"><span class="ln">23</span><span class="cl">    .filter(pl.col(&#34;value&#34;) &gt; 100)
</span></span><span class="line"><span class="ln">24</span><span class="cl">    .group_by(&#34;category&#34;)
</span></span><span class="line"><span class="ln">25</span><span class="cl">    .agg(pl.col(&#34;value&#34;).sum())
</span></span><span class="line"><span class="ln">26</span><span class="cl">    .collect()
</span></span><span class="line"><span class="ln">27</span><span class="cl">)</span></span></code></pre></div><h3 id="ruff">Ruff</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Ruff - 超快的 Python linter
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">用途：
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">- Python 程式碼檢查
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">- 取代 flake8、isort、pyupgrade 等
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">特點：
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">- 比 flake8 快 10-100x
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">- 單一工具取代多個 linter
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">為什麼選擇 Rust：
</span></span><span class="line"><span class="ln">12</span><span class="cl">- 需要處理大型程式碼庫
</span></span><span class="line"><span class="ln">13</span><span class="cl">- 需要快速的回饋（IDE 整合）
</span></span><span class="line"><span class="ln">14</span><span class="cl">- 字串處理效能關鍵
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">效能數據：
</span></span><span class="line"><span class="ln">17</span><span class="cl">- CPython 程式碼庫（約 60 萬行）
</span></span><span class="line"><span class="ln">18</span><span class="cl">- Ruff: 0.29 秒
</span></span><span class="line"><span class="ln">19</span><span class="cl">- flake8: 22 秒</span></span></code></pre></div><h3 id="pydantic-core">pydantic-core</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">pydantic-core - Pydantic v2 的核心
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">用途：
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">- 資料驗證和序列化
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">- 廣泛用於 FastAPI
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">特點：
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">- Pydantic v2 比 v1 快 5-50x
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">- 核心驗證邏輯用 Rust 重寫
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">為什麼選擇 Rust：
</span></span><span class="line"><span class="ln">12</span><span class="cl">- 驗證邏輯被頻繁呼叫
</span></span><span class="line"><span class="ln">13</span><span class="cl">- 需要處理各種邊界情況
</span></span><span class="line"><span class="ln">14</span><span class="cl">- 需要安全地處理任意輸入</span></span></code></pre></div><hr>
<h2 id="評估何時選擇-rust">【評估】何時選擇 Rust</h2>
<h3 id="適合使用-rust-的場景">適合使用 Rust 的場景</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">應該考慮 Rust：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">1. 效能關鍵的程式碼
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">   - 大量數值計算
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">   - 頻繁呼叫的函式
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">   - 處理大型資料集
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">2. 需要安全地處理任意輸入
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   - 解析使用者提供的資料
</span></span><span class="line"><span class="ln">10</span><span class="cl">   - 網路協議處理
</span></span><span class="line"><span class="ln">11</span><span class="cl">   - 檔案格式解析
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">3. 需要並行處理
</span></span><span class="line"><span class="ln">14</span><span class="cl">   - 多執行緒計算
</span></span><span class="line"><span class="ln">15</span><span class="cl">   - 非同步 I/O
</span></span><span class="line"><span class="ln">16</span><span class="cl">   - 需要避免 GIL
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">4. 長期維護的核心函式庫
</span></span><span class="line"><span class="ln">19</span><span class="cl">   - 減少記憶體相關 bug
</span></span><span class="line"><span class="ln">20</span><span class="cl">   - 更容易重構
</span></span><span class="line"><span class="ln">21</span><span class="cl">   - 跨語言共享
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl">5. 跨平台發布
</span></span><span class="line"><span class="ln">24</span><span class="cl">   - Rust 交叉編譯支援好
</span></span><span class="line"><span class="ln">25</span><span class="cl">   - 減少平台特定 bug</span></span></code></pre></div><h3 id="不太適合-rust-的場景">不太適合 Rust 的場景</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">可能不需要 Rust：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">1. 快速原型開發
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">   - Python 本身就夠用
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">   - 學習成本高
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">2. 已有 C/C++ 程式碼
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">   - 直接用 pybind11 包裝
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   - 除非需要大幅修改
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">3. 團隊不熟悉 Rust
</span></span><span class="line"><span class="ln">12</span><span class="cl">   - 學習曲線陡峭
</span></span><span class="line"><span class="ln">13</span><span class="cl">   - 維護成本考量
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">4. 效能不是瓶頸
</span></span><span class="line"><span class="ln">16</span><span class="cl">   - 先用 profiler 確認
</span></span><span class="line"><span class="ln">17</span><span class="cl">   - 可能 Python 優化就夠了
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">5. 只需要呼叫現有 C 函式庫
</span></span><span class="line"><span class="ln">20</span><span class="cl">   - ctypes/cffi 更簡單
</span></span><span class="line"><span class="ln">21</span><span class="cl">   - 不需要額外語言</span></span></code></pre></div><h3 id="決策流程">決策流程</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">需要 Python 擴展？
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">│
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── 有現有 C/C++ 程式碼？
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   ├── 是 → pybind11/Cython
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│   └── 否 ↓
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">│
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── 效能是主要考量？
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">│   ├── 否 → 純 Python 或 Cython
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">│   └── 是 ↓
</span></span><span class="line"><span class="ln">10</span><span class="cl">│
</span></span><span class="line"><span class="ln">11</span><span class="cl">├── 需要並行安全？
</span></span><span class="line"><span class="ln">12</span><span class="cl">│   ├── 是 → Rust (PyO3)
</span></span><span class="line"><span class="ln">13</span><span class="cl">│   └── 否 ↓
</span></span><span class="line"><span class="ln">14</span><span class="cl">│
</span></span><span class="line"><span class="ln">15</span><span class="cl">├── 團隊熟悉 Rust？
</span></span><span class="line"><span class="ln">16</span><span class="cl">│   ├── 是 → Rust (PyO3)
</span></span><span class="line"><span class="ln">17</span><span class="cl">│   └── 否 → Cython 或學習 Rust
</span></span><span class="line"><span class="ln">18</span><span class="cl">│
</span></span><span class="line"><span class="ln">19</span><span class="cl">└── 長期維護的核心程式碼？
</span></span><span class="line"><span class="ln">20</span><span class="cl">    ├── 是 → 考慮 Rust
</span></span><span class="line"><span class="ln">21</span><span class="cl">    └── 否 → Cython 可能更實際</span></span></code></pre></div><hr>
<h2 id="入門rust-基礎概念">【入門】Rust 基礎概念</h2>
<h3 id="給-python-開發者的快速入門">給 Python 開發者的快速入門</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// 變數與型別
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">basics</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="c1">// 不可變變數（預設）
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="c1">// x = 6;  // 錯誤！
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="c1">// 可變變數
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">6</span><span class="p">;</span><span class="w">  </span><span class="c1">// OK
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="c1">// 型別推斷
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span><span class="w">       </span><span class="c1">// i32
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">pi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">3.14</span><span class="p">;</span><span class="w">    </span><span class="c1">// f64
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="c1">// 明確型別
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span>: <span class="kt">i64</span> <span class="o">=</span><span class="w"> </span><span class="mi">100</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">b</span>: <span class="kt">f32</span> <span class="o">=</span><span class="w"> </span><span class="mf">3.14</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w"></span><span class="c1">// 函式
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span>: <span class="kt">i32</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="kt">i32</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">i32</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">    </span><span class="n">a</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="w">  </span><span class="c1">// 沒有分號 = 回傳值
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w"></span><span class="c1">// 結構體（類似 Python class）
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"></span><span class="k">struct</span> <span class="nc">Point</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">    </span><span class="n">x</span>: <span class="kt">f64</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">    </span><span class="n">y</span>: <span class="kt">f64</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Point</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">    </span><span class="c1">// 關聯函式（類似 classmethod）
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">x</span>: <span class="kt">f64</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="kt">f64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">        </span><span class="n">Point</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">    </span><span class="c1">// 方法
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">distance</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">other</span>: <span class="kp">&amp;</span><span class="nc">Point</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">dx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">x</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">dy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">y</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">        </span><span class="p">(</span><span class="n">dx</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">dx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">dy</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">dy</span><span class="p">).</span><span class="n">sqrt</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w"></span><span class="c1">// 列舉（比 Python enum 更強大）
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="c1"></span><span class="k">enum</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">    </span><span class="nb">Some</span><span class="p">(</span><span class="n">T</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">    </span><span class="nb">None</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w"></span><span class="k">enum</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="w"> </span><span class="n">E</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">T</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">    </span><span class="nb">Err</span><span class="p">(</span><span class="n">E</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w"></span><span class="c1">// 模式匹配
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">handle_option</span><span class="p">(</span><span class="n">opt</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="w">    </span><span class="k">match</span><span class="w"> </span><span class="n">opt</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="w">        </span><span class="nb">Some</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;有值: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="w">        </span><span class="nb">None</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;沒有值&#34;</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="w"></span><span class="c1">// 迭代器（類似 Python generator）
</span></span></span><span class="line"><span class="ln">65</span><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">iterators</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">];</span><span class="w">
</span></span></span><span class="line"><span class="ln">67</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="w">    </span><span class="c1">// 類似 Python 的 list comprehension
</span></span></span><span class="line"><span class="ln">69</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">doubled</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">2</span><span class="p">).</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">71</span><span class="cl"><span class="w">    </span><span class="c1">// 類似 Python 的 filter
</span></span></span><span class="line"><span class="ln">72</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">evens</span>: <span class="nb">Vec</span><span class="o">&lt;&amp;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="o">*</span><span class="n">x</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">).</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">73</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="python-vs-rust-語法對照">Python vs Rust 語法對照</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Python                          Rust
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">──────────────────────────────────────────────────────
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">x = 5                           let x = 5;
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">x = 5  # mutable                let mut x = 5;
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">def foo(x):                     fn foo(x: i32) -&gt; i32 {
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    return x + 1                    x + 1
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">                                }
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">class Point:                    struct Point {
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    def __init__(self, x, y):       x: f64,
</span></span><span class="line"><span class="ln">10</span><span class="cl">        self.x = x                  y: f64,
</span></span><span class="line"><span class="ln">11</span><span class="cl">        self.y = y              }
</span></span><span class="line"><span class="ln">12</span><span class="cl">[x*2 for x in lst]              lst.iter().map(|x| x*2).collect()
</span></span><span class="line"><span class="ln">13</span><span class="cl">if x is None:                   if x.is_none() {
</span></span><span class="line"><span class="ln">14</span><span class="cl">    ...                             ...
</span></span><span class="line"><span class="ln">15</span><span class="cl">for i in range(10):             for i in 0..10 {
</span></span><span class="line"><span class="ln">16</span><span class="cl">    ...                             ...
</span></span><span class="line"><span class="ln">17</span><span class="cl">try: ... except:                match result {
</span></span><span class="line"><span class="ln">18</span><span class="cl">    ...                             Ok(v) =&gt; ...,
</span></span><span class="line"><span class="ln">19</span><span class="cl">                                    Err(e) =&gt; ...,
</span></span><span class="line"><span class="ln">20</span><span class="cl">                                }</span></span></code></pre></div><hr>
<h2 id="思考題">思考題</h2>
<ol>
<li>Rust 的所有權系統如何與 Python 的垃圾回收協調？PyO3 如何處理這個問題？</li>
<li>為什麼許多高效能 Python 函式庫選擇用 Rust 重寫而不是 C++？</li>
<li>學習 Rust 對 Python 開發者有什麼長期價值？</li>
</ol>
<h2 id="實作練習">實作練習</h2>
<ol>
<li>安裝 Rust 並完成官方教學「rustlings」的前 20 個練習</li>
<li>比較用 Python、Cython 和 Rust 實現 Fibonacci 函式的效能</li>
<li>研究一個用 Rust 寫的 Python 函式庫（如 Polars），理解其專案結構</li>
</ol>
<h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://doc.rust-lang.org/book/">The Rust Programming Language</a></li>
<li><a href="https://doc.rust-lang.org/rust-by-example/">Rust by Example</a></li>
<li><a href="https://pyo3.rs/">PyO3 User Guide</a></li>
<li><a href="https://arewefastyet.rs/">Are We Fast Yet? - Rust Performance Benchmarks</a></li>
</ul>
<hr>
<p>下一章：<a href="/blog/python-advanced/06-rust-extensions/pyo3-basics/" data-link-title="5.2 PyO3 基礎" data-link-desc="使用 PyO3 建立 Rust 與 Python 的綁定">PyO3 基礎</a></p>
]]></content:encoded></item><item><title>案例：Rust 正則表達式</title><link>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/rust-regex/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/rust-regex/</guid><description>&lt;p>本案例基於 &lt;code>.claude/lib/hook_validator.py&lt;/code> 的實際程式碼，展示如何用 Rust 的 regex crate 加速模式匹配。&lt;/p>
&lt;h2 id="先備知識">先備知識&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/" data-link-title="模組六：用 Rust 擴展 Python" data-link-desc="學習使用 PyO3 和 Maturin 用 Rust 擴展 Python">模組六：用 Rust 擴展 Python&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/pyo3-parser/" data-link-title="案例：PyO3 文字解析" data-link-desc="用 PyO3 和 Rust 實現高效能的 Markdown 連結解析器">6.1 PyO3 文字解析&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="問題背景">問題背景&lt;/h2>
&lt;h3 id="現有設計">現有設計&lt;/h3>
&lt;p>&lt;code>hook_validator.py&lt;/code> 使用 Python 的 re 模組進行多種模式匹配驗證：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">re&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Optional&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pathlib&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">HookValidator&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Hook 合規性驗證器&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="c1"># Pattern definitions for various validation checks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="n">HOOK_IO_PATTERNS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;from\s+hook_io\s+import&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;from\s+lib\.hook_io\s+import&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> &lt;span class="n">HOOK_LOGGING_PATTERNS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;from\s+hook_logging\s+import&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;from\s+lib\.hook_logging\s+import&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> &lt;span class="n">CONFIG_LOADER_PATTERNS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;from\s+config_loader\s+import&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;from\s+lib\.config_loader\s+import&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl"> &lt;span class="n">GIT_UTILS_PATTERNS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;from\s+git_utils\s+import&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;from\s+lib\.git_utils\s+import&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl"> &lt;span class="n">OUTPUT_PATTERNS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;write_hook_output\s*\(&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;create_pretooluse_output\s*\(&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;create_posttooluse_output\s*\(&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl"> &lt;span class="n">BAD_OUTPUT_PATTERNS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s1">&amp;#39;print\s*\(\s*json\.dumps\s*\(&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s1">&amp;#39;sys\.stdout\.write\s*\(\s*json\.dumps\s*\(&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl"> &lt;span class="n">VALID_NAME_PATTERNS&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl"> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;^[a-z0-9](/python-advanced/06-rust-extensions/case-studies/rust-regex/[a-z0-9\-_]*[a-z0-9])?\.py$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">43&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">44&lt;/span>&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">_has_import&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">patterns&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">45&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Check if content matches any of the import patterns&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">46&lt;/span>&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">any&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">47&lt;/span>&lt;span class="cl"> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">48&lt;/span>&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">pattern&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">patterns&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">49&lt;/span>&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">50&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">51&lt;/span>&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">_matches_pattern&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">patterns&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">52&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Check if content matches any pattern&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">53&lt;/span>&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">any&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">54&lt;/span>&lt;span class="cl"> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">55&lt;/span>&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">pattern&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">patterns&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">56&lt;/span>&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">57&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">58&lt;/span>&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">check_naming_convention&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">hook_path&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Path&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">59&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Validate file naming convention&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">60&lt;/span>&lt;span class="cl"> &lt;span class="n">filename&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hook_path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">61&lt;/span>&lt;span class="cl"> &lt;span class="n">valid_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">any&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">62&lt;/span>&lt;span class="cl"> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="k">match&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">filename&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">63&lt;/span>&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">pattern&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">VALID_NAME_PATTERNS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">64&lt;/span>&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">65&lt;/span>&lt;span class="cl"> &lt;span class="c1"># ... validation logic&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這段程式碼展示了幾個核心問題：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>重複編譯&lt;/strong>：每次呼叫 &lt;code>re.search()&lt;/code> 或 &lt;code>re.match()&lt;/code> 都可能重新編譯正則表達式&lt;/li>
&lt;li>&lt;strong>多模式匹配&lt;/strong>：需要遍歷多個模式逐一檢查&lt;/li>
&lt;li>&lt;strong>混合使用場景&lt;/strong>：部分用於 &lt;code>match&lt;/code>（從頭匹配），部分用於 &lt;code>search&lt;/code>（任意位置）&lt;/li>
&lt;/ol>
&lt;h3 id="效能限制">效能限制&lt;/h3>
&lt;p>Python re 模組的限制：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>限制&lt;/th>
 &lt;th>說明&lt;/th>
 &lt;th>影響&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>回溯型引擎&lt;/strong>&lt;/td>
 &lt;td>NFA with backtracking&lt;/td>
 &lt;td>某些模式可能導致指數級時間複雜度&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>解釋器開銷&lt;/strong>&lt;/td>
 &lt;td>每次匹配都經過 Python 呼叫&lt;/td>
 &lt;td>大量匹配時累積顯著延遲&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>無硬體加速&lt;/strong>&lt;/td>
 &lt;td>純軟體實作&lt;/td>
 &lt;td>無法利用 SIMD 等現代 CPU 特性&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>GIL 限制&lt;/strong>&lt;/td>
 &lt;td>受 Global Interpreter Lock 影響&lt;/td>
 &lt;td>多執行緒場景效能受限&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h4 id="病態輸入示例">病態輸入示例&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">re&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># Pathological pattern: catastrophic backtracking&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="n">pattern&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;(a+)+b&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="n">text&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;a&amp;#34;&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">25&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s2">&amp;#34;c&amp;#34;&lt;/span> &lt;span class="c1"># No match, triggers backtracking&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="n">start&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Python re: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">elapsed&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">s&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># May take several seconds!&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="進階解決方案">進階解決方案&lt;/h2>
&lt;h3 id="設計目標">設計目標&lt;/h3>
&lt;ol>
&lt;li>用 Rust regex crate 取代 Python re&lt;/li>
&lt;li>利用 Rust regex 的 DFA 引擎確保線性時間複雜度&lt;/li>
&lt;li>使用 &lt;code>RegexSet&lt;/code> 實現高效批次驗證&lt;/li>
&lt;li>預編譯正則表達式，避免重複編譯開銷&lt;/li>
&lt;/ol>
&lt;h3 id="實作步驟">實作步驟&lt;/h3>
&lt;h4 id="步驟-1建立專案結構">步驟 1：建立專案結構&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># Create new maturin project&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">maturin new hook_validator_rs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nb">cd&lt;/span> hook_validator_rs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1"># Project structure&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">hook_validator_rs/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">├── Cargo.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">├── pyproject.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">└── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> └── lib.rs&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>編輯 &lt;code>Cargo.toml&lt;/code>：&lt;/p></description><content:encoded><![CDATA[<p>本案例基於 <code>.claude/lib/hook_validator.py</code> 的實際程式碼，展示如何用 Rust 的 regex crate 加速模式匹配。</p>
<h2 id="先備知識">先備知識</h2>
<ul>
<li><a href="/blog/python-advanced/06-rust-extensions/" data-link-title="模組六：用 Rust 擴展 Python" data-link-desc="學習使用 PyO3 和 Maturin 用 Rust 擴展 Python">模組六：用 Rust 擴展 Python</a></li>
<li><a href="/blog/python-advanced/06-rust-extensions/case-studies/pyo3-parser/" data-link-title="案例：PyO3 文字解析" data-link-desc="用 PyO3 和 Rust 實現高效能的 Markdown 連結解析器">6.1 PyO3 文字解析</a></li>
</ul>
<h2 id="問題背景">問題背景</h2>
<h3 id="現有設計">現有設計</h3>
<p><code>hook_validator.py</code> 使用 Python 的 re 模組進行多種模式匹配驗證：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Optional</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">class</span> <span class="nc">HookValidator</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Hook 合規性驗證器&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="c1"># Pattern definitions for various validation checks</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">HOOK_IO_PATTERNS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;from\s+hook_io\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;from\s+lib\.hook_io\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">HOOK_LOGGING_PATTERNS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;from\s+hook_logging\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;from\s+lib\.hook_logging\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="n">CONFIG_LOADER_PATTERNS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;from\s+config_loader\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;from\s+lib\.config_loader\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="n">GIT_UTILS_PATTERNS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;from\s+git_utils\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;from\s+lib\.git_utils\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="n">OUTPUT_PATTERNS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;write_hook_output\s*\(&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;create_pretooluse_output\s*\(&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;create_posttooluse_output\s*\(&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">
</span></span><span class="line"><span class="ln">35</span><span class="cl">    <span class="n">BAD_OUTPUT_PATTERNS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">        <span class="sa">r</span><span class="s1">&#39;print\s*\(\s*json\.dumps\s*\(&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">        <span class="sa">r</span><span class="s1">&#39;sys\.stdout\.write\s*\(\s*json\.dumps\s*\(&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">
</span></span><span class="line"><span class="ln">40</span><span class="cl">    <span class="n">VALID_NAME_PATTERNS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">        <span class="sa">r</span><span class="s2">&#34;^[a-z0-9](/python-advanced/06-rust-extensions/case-studies/rust-regex/[a-z0-9\-_]*[a-z0-9])?\.py$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">
</span></span><span class="line"><span class="ln">44</span><span class="cl">    <span class="k">def</span> <span class="nf">_has_import</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">patterns</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Check if content matches any of the import patterns&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">        <span class="k">return</span> <span class="nb">any</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">            <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">            <span class="k">for</span> <span class="n">pattern</span> <span class="ow">in</span> <span class="n">patterns</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl">
</span></span><span class="line"><span class="ln">51</span><span class="cl">    <span class="k">def</span> <span class="nf">_matches_pattern</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">patterns</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Check if content matches any pattern&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl">        <span class="k">return</span> <span class="nb">any</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">            <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl">            <span class="k">for</span> <span class="n">pattern</span> <span class="ow">in</span> <span class="n">patterns</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl">
</span></span><span class="line"><span class="ln">58</span><span class="cl">    <span class="k">def</span> <span class="nf">check_naming_convention</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">hook_path</span><span class="p">:</span> <span class="n">Path</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="nb">dict</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">59</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Validate file naming convention&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">60</span><span class="cl">        <span class="n">filename</span> <span class="o">=</span> <span class="n">hook_path</span><span class="o">.</span><span class="n">name</span>
</span></span><span class="line"><span class="ln">61</span><span class="cl">        <span class="n">valid_name</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">62</span><span class="cl">            <span class="n">re</span><span class="o">.</span><span class="k">match</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">63</span><span class="cl">            <span class="k">for</span> <span class="n">pattern</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">VALID_NAME_PATTERNS</span>
</span></span><span class="line"><span class="ln">64</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">65</span><span class="cl">        <span class="c1"># ... validation logic</span></span></span></code></pre></div><p>這段程式碼展示了幾個核心問題：</p>
<ol>
<li><strong>重複編譯</strong>：每次呼叫 <code>re.search()</code> 或 <code>re.match()</code> 都可能重新編譯正則表達式</li>
<li><strong>多模式匹配</strong>：需要遍歷多個模式逐一檢查</li>
<li><strong>混合使用場景</strong>：部分用於 <code>match</code>（從頭匹配），部分用於 <code>search</code>（任意位置）</li>
</ol>
<h3 id="效能限制">效能限制</h3>
<p>Python re 模組的限制：</p>
<table>
  <thead>
      <tr>
          <th>限制</th>
          <th>說明</th>
          <th>影響</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>回溯型引擎</strong></td>
          <td>NFA with backtracking</td>
          <td>某些模式可能導致指數級時間複雜度</td>
      </tr>
      <tr>
          <td><strong>解釋器開銷</strong></td>
          <td>每次匹配都經過 Python 呼叫</td>
          <td>大量匹配時累積顯著延遲</td>
      </tr>
      <tr>
          <td><strong>無硬體加速</strong></td>
          <td>純軟體實作</td>
          <td>無法利用 SIMD 等現代 CPU 特性</td>
      </tr>
      <tr>
          <td><strong>GIL 限制</strong></td>
          <td>受 Global Interpreter Lock 影響</td>
          <td>多執行緒場景效能受限</td>
      </tr>
  </tbody>
</table>
<h4 id="病態輸入示例">病態輸入示例</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># Pathological pattern: catastrophic backtracking</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">pattern</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">&#34;(a+)+b&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">text</span> <span class="o">=</span> <span class="s2">&#34;a&#34;</span> <span class="o">*</span> <span class="mi">25</span> <span class="o">+</span> <span class="s2">&#34;c&#34;</span>  <span class="c1"># No match, triggers backtracking</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">elapsed</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Python re: </span><span class="si">{</span><span class="n">elapsed</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">s&#34;</span><span class="p">)</span>  <span class="c1"># May take several seconds!</span></span></span></code></pre></div><h2 id="進階解決方案">進階解決方案</h2>
<h3 id="設計目標">設計目標</h3>
<ol>
<li>用 Rust regex crate 取代 Python re</li>
<li>利用 Rust regex 的 DFA 引擎確保線性時間複雜度</li>
<li>使用 <code>RegexSet</code> 實現高效批次驗證</li>
<li>預編譯正則表達式，避免重複編譯開銷</li>
</ol>
<h3 id="實作步驟">實作步驟</h3>
<h4 id="步驟-1建立專案結構">步驟 1：建立專案結構</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># Create new maturin project</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">maturin new hook_validator_rs
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nb">cd</span> hook_validator_rs
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># Project structure</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">hook_validator_rs/
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── Cargo.toml
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── pyproject.toml
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">└── src/
</span></span><span class="line"><span class="ln">10</span><span class="cl">    └── lib.rs</span></span></code></pre></div><p>編輯 <code>Cargo.toml</code>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">package</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;hook_validator_rs&#34;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">edition</span> <span class="p">=</span> <span class="s2">&#34;2021&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">lib</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;hook_validator_rs&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">crate-type</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;cdylib&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.22&#34;</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">regex</span> <span class="p">=</span> <span class="s2">&#34;1.10&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">once_cell</span> <span class="p">=</span> <span class="s2">&#34;1.19&#34;</span></span></span></code></pre></div><h4 id="步驟-2定義預編譯正則表達式">步驟 2：定義預編譯正則表達式</h4>
<p>使用 <code>once_cell::sync::Lazy</code> 實現執行緒安全的延遲初始化：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">once_cell</span>::<span class="n">sync</span>::<span class="n">Lazy</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">regex</span>::<span class="p">{</span><span class="n">Regex</span><span class="p">,</span><span class="w"> </span><span class="n">RegexSet</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="c1">// Pre-compiled individual patterns
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"></span><span class="k">static</span><span class="w"> </span><span class="no">HOOK_IO_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+hook_io\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+lib\.hook_io\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="p">]).</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid regex pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">HOOK_LOGGING_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+hook_logging\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+lib\.hook_logging\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="p">]).</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid regex pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">CONFIG_LOADER_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+config_loader\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+lib\.config_loader\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">    </span><span class="p">]).</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid regex pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">GIT_UTILS_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+git_utils\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+lib\.git_utils\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">    </span><span class="p">]).</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid regex pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">OUTPUT_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;write_hook_output\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;create_pretooluse_output\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;create_posttooluse_output\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">    </span><span class="p">]).</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid regex pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">BAD_OUTPUT_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;print\s*\(\s*json\.dumps\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;sys\.stdout\.write\s*\(\s*json\.dumps\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">    </span><span class="p">]).</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid regex pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w"></span><span class="c1">// For filename validation (anchored match)
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="c1"></span><span class="k">static</span><span class="w"> </span><span class="no">VALID_NAME_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;^[a-z0-9](/python-advanced/06-rust-extensions/case-studies/rust-regex/[a-z0-9\-_]*[a-z0-9])?\.py$&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid regex pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w"></span><span class="p">});</span></span></span></code></pre></div><h5 id="為什麼用-once_cellsynclazy">為什麼用 <code>once_cell::sync::Lazy</code>？</h5>
<ul>
<li><strong>執行緒安全</strong>：<code>Lazy</code> 確保初始化只執行一次，即使多執行緒同時存取</li>
<li><strong>延遲初始化</strong>：只在第一次使用時編譯正則表達式</li>
<li><strong>零執行時開銷</strong>：初始化後的存取是零成本的</li>
</ul>
<h4 id="步驟-3實作批次匹配邏輯">步驟 3：實作批次匹配邏輯</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="sd">/// Result of validating import patterns in source code
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="sd"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">ImportCheckResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_hook_io</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_hook_logging</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_config_loader</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_git_utils</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_good_output</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_bad_output</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">ImportCheckResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">            </span><span class="s">&#34;ImportCheckResult(hook_io=</span><span class="si">{}</span><span class="s">, logging=</span><span class="si">{}</span><span class="s">, config=</span><span class="si">{}</span><span class="s">, git=</span><span class="si">{}</span><span class="s">, good_out=</span><span class="si">{}</span><span class="s">, bad_out=</span><span class="si">{}</span><span class="s">)&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_hook_io</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">has_hook_logging</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_config_loader</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">has_git_utils</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_good_output</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">has_bad_output</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">        </span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w"></span><span class="sd">/// Check all import patterns in a single pass through the content
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">check_imports</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">ImportCheckResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">    </span><span class="n">ImportCheckResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">        </span><span class="n">has_hook_io</span>: <span class="nc">HOOK_IO_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">        </span><span class="n">has_hook_logging</span>: <span class="nc">HOOK_LOGGING_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">        </span><span class="n">has_config_loader</span>: <span class="nc">CONFIG_LOADER_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">        </span><span class="n">has_git_utils</span>: <span class="nc">GIT_UTILS_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">        </span><span class="n">has_good_output</span>: <span class="nc">OUTPUT_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">        </span><span class="n">has_bad_output</span>: <span class="nc">BAD_OUTPUT_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w"></span><span class="sd">/// Validate filename against naming convention
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">is_valid_hook_name</span><span class="p">(</span><span class="n">filename</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">    </span><span class="no">VALID_NAME_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w"></span><span class="sd">/// Check which specific patterns matched (for detailed reporting)
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">get_matched_patterns</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">pattern_group</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">regex_set</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">pattern_group</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="w">        </span><span class="s">&#34;hook_io&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;*</span><span class="no">HOOK_IO_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="w">        </span><span class="s">&#34;hook_logging&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;*</span><span class="no">HOOK_LOGGING_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="w">        </span><span class="s">&#34;config_loader&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;*</span><span class="no">CONFIG_LOADER_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="w">        </span><span class="s">&#34;git_utils&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;*</span><span class="no">GIT_UTILS_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="w">        </span><span class="s">&#34;output&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;*</span><span class="no">OUTPUT_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="w">        </span><span class="s">&#34;bad_output&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;*</span><span class="no">BAD_OUTPUT_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="w">        </span><span class="n">_</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[],</span><span class="w">
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="w">    </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln">65</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="w">    </span><span class="n">regex_set</span><span class="p">.</span><span class="n">matches</span><span class="p">(</span><span class="n">content</span><span class="p">).</span><span class="n">iter</span><span class="p">().</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">67</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h4 id="步驟-4進階批次驗證-api">步驟 4：進階批次驗證 API</h4>
<p>對於需要一次驗證大量檔案的場景，提供更高效的批次 API：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="sd">/// Batch validation result for multiple files
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="sd"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">BatchValidationResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">results</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">ImportCheckResult</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">valid_names</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">BatchValidationResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;BatchValidationResult(</span><span class="si">{}</span><span class="s"> files)&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">results</span><span class="p">.</span><span class="n">len</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="sd">/// Get files that are missing hook_io import
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">files_missing_hook_io</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">results</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="o">!</span><span class="n">r</span><span class="p">.</span><span class="n">has_hook_io</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="sd">/// Get files with bad output patterns
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">files_with_bad_output</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">results</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">has_bad_output</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w"></span><span class="sd">/// Validate multiple files in batch
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="sd">/// This is more efficient than calling check_imports for each file
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="sd">/// because it can potentially parallelize the work.
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">validate_batch</span><span class="p">(</span><span class="n">files</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">String</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">BatchValidationResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">results</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">ImportCheckResult</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">content</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w"> </span><span class="n">check_imports</span><span class="p">(</span><span class="n">content</span><span class="p">)))</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">valid_names</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">keys</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">path</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">filename</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">path</span><span class="p">.</span><span class="n">rsplit</span><span class="p">(</span><span class="sc">&#39;/&#39;</span><span class="p">).</span><span class="n">next</span><span class="p">().</span><span class="n">unwrap_or</span><span class="p">(</span><span class="n">path</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">            </span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w"> </span><span class="n">is_valid_hook_name</span><span class="p">(</span><span class="n">filename</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w">    </span><span class="n">BatchValidationResult</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">results</span><span class="p">,</span><span class="w"> </span><span class="n">valid_names</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h4 id="步驟-5pyo3-模組導出">步驟 5：PyO3 模組導出</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="sd">/// Rust-powered hook validator with pre-compiled regex patterns
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="sd"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">hook_validator_rs</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">check_imports</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">is_valid_hook_name</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">get_matched_patterns</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">validate_batch</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">ImportCheckResult</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">BatchValidationResult</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h4 id="步驟-6python-端整合">步驟 6：Python 端整合</h4>
<p>在 Python 端無縫整合 Rust 模組：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">  1</span><span class="cl"><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="s2">Hook 合規性驗證工具（Rust 加速版）
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="s2">This module provides a drop-in replacement for the pure Python
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="s2">hook_validator, using Rust regex crate for pattern matching.
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">  7</span><span class="cl">
</span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Optional</span>
</span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span><span class="p">,</span> <span class="n">field</span>
</span></span><span class="line"><span class="ln"> 11</span><span class="cl">
</span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="c1"># Try to import Rust extension, fall back to pure Python</span>
</span></span><span class="line"><span class="ln"> 13</span><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 14</span><span class="cl">    <span class="kn">import</span> <span class="nn">hook_validator_rs</span> <span class="k">as</span> <span class="nn">_rs</span>
</span></span><span class="line"><span class="ln"> 15</span><span class="cl">    <span class="n">_USE_RUST</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 17</span><span class="cl">    <span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln"> 18</span><span class="cl">    <span class="n">_USE_RUST</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="ln"> 19</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Warning: Rust extension not available, using pure Python&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 20</span><span class="cl">
</span></span><span class="line"><span class="ln"> 21</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln"> 22</span><span class="cl"><span class="k">class</span> <span class="nc">ValidationIssue</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 23</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Validation issue description&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 24</span><span class="cl">    <span class="n">level</span><span class="p">:</span> <span class="nb">str</span>  <span class="c1"># &#34;error&#34; | &#34;warning&#34; | &#34;info&#34;</span>
</span></span><span class="line"><span class="ln"> 25</span><span class="cl">    <span class="n">message</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 26</span><span class="cl">    <span class="n">line</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln"> 27</span><span class="cl">    <span class="n">suggestion</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln"> 28</span><span class="cl">
</span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="k">class</span> <span class="nc">ValidationResult</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 31</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Validation result for a single hook&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 32</span><span class="cl">    <span class="n">hook_path</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="ln"> 33</span><span class="cl">    <span class="n">issues</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">ValidationIssue</span><span class="p">]</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span><span class="n">default_factory</span><span class="o">=</span><span class="nb">list</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 34</span><span class="cl">    <span class="n">is_compliant</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="ln"> 35</span><span class="cl">
</span></span><span class="line"><span class="ln"> 36</span><span class="cl">    <span class="k">def</span> <span class="nf">__post_init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 37</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">is_compliant</span> <span class="o">=</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 38</span><span class="cl">            <span class="n">issue</span><span class="o">.</span><span class="n">level</span> <span class="o">==</span> <span class="s2">&#34;error&#34;</span> <span class="k">for</span> <span class="n">issue</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">issues</span>
</span></span><span class="line"><span class="ln"> 39</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln"> 40</span><span class="cl">
</span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="k">class</span> <span class="nc">HookValidator</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 42</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Hook compliance validator with optional Rust acceleration&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 43</span><span class="cl">
</span></span><span class="line"><span class="ln"> 44</span><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">project_root</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 45</span><span class="cl">        <span class="k">if</span> <span class="n">project_root</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 46</span><span class="cl">            <span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="ln"> 47</span><span class="cl">            <span class="n">project_root</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;CLAUDE_PROJECT_DIR&#34;</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">())</span>
</span></span><span class="line"><span class="ln"> 48</span><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">project_root</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">project_root</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 49</span><span class="cl">
</span></span><span class="line"><span class="ln"> 50</span><span class="cl">    <span class="k">def</span> <span class="nf">check_lib_imports</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 51</span><span class="cl">        <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 52</span><span class="cl">        <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 53</span><span class="cl">        <span class="n">hook_path</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln"> 54</span><span class="cl">    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">ValidationIssue</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 55</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Check shared module imports using Rust regex&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 56</span><span class="cl">        <span class="n">issues</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln"> 57</span><span class="cl">
</span></span><span class="line"><span class="ln"> 58</span><span class="cl">        <span class="k">if</span> <span class="n">_USE_RUST</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 59</span><span class="cl">            <span class="c1"># Use Rust-accelerated pattern matching</span>
</span></span><span class="line"><span class="ln"> 60</span><span class="cl">            <span class="n">result</span> <span class="o">=</span> <span class="n">_rs</span><span class="o">.</span><span class="n">check_imports</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 61</span><span class="cl">
</span></span><span class="line"><span class="ln"> 62</span><span class="cl">            <span class="k">if</span> <span class="ow">not</span> <span class="n">result</span><span class="o">.</span><span class="n">has_hook_io</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 63</span><span class="cl">                <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 64</span><span class="cl">                    <span class="n">level</span><span class="o">=</span><span class="s2">&#34;warning&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 65</span><span class="cl">                    <span class="n">message</span><span class="o">=</span><span class="s2">&#34;Missing hook_io import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 66</span><span class="cl">                    <span class="n">suggestion</span><span class="o">=</span><span class="s2">&#34;Add: from hook_io import read_hook_input, write_hook_output&#34;</span>
</span></span><span class="line"><span class="ln"> 67</span><span class="cl">                <span class="p">))</span>
</span></span><span class="line"><span class="ln"> 68</span><span class="cl">
</span></span><span class="line"><span class="ln"> 69</span><span class="cl">            <span class="k">if</span> <span class="ow">not</span> <span class="n">result</span><span class="o">.</span><span class="n">has_hook_logging</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 70</span><span class="cl">                <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 71</span><span class="cl">                    <span class="n">level</span><span class="o">=</span><span class="s2">&#34;info&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 72</span><span class="cl">                    <span class="n">message</span><span class="o">=</span><span class="s2">&#34;Missing hook_logging import (recommended)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 73</span><span class="cl">                    <span class="n">suggestion</span><span class="o">=</span><span class="s2">&#34;Add: from hook_logging import setup_hook_logging&#34;</span>
</span></span><span class="line"><span class="ln"> 74</span><span class="cl">                <span class="p">))</span>
</span></span><span class="line"><span class="ln"> 75</span><span class="cl">
</span></span><span class="line"><span class="ln"> 76</span><span class="cl">            <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">has_bad_output</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 77</span><span class="cl">                <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 78</span><span class="cl">                    <span class="n">level</span><span class="o">=</span><span class="s2">&#34;warning&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 79</span><span class="cl">                    <span class="n">message</span><span class="o">=</span><span class="s2">&#34;Using print(json.dumps(...)) instead of write_hook_output()&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 80</span><span class="cl">                    <span class="n">suggestion</span><span class="o">=</span><span class="s2">&#34;Replace with: write_hook_output(output_dict)&#34;</span>
</span></span><span class="line"><span class="ln"> 81</span><span class="cl">                <span class="p">))</span>
</span></span><span class="line"><span class="ln"> 82</span><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 83</span><span class="cl">            <span class="c1"># Fallback to pure Python regex</span>
</span></span><span class="line"><span class="ln"> 84</span><span class="cl">            <span class="n">issues</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_check_imports_python</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">hook_path</span><span class="p">))</span>
</span></span><span class="line"><span class="ln"> 85</span><span class="cl">
</span></span><span class="line"><span class="ln"> 86</span><span class="cl">        <span class="k">return</span> <span class="n">issues</span>
</span></span><span class="line"><span class="ln"> 87</span><span class="cl">
</span></span><span class="line"><span class="ln"> 88</span><span class="cl">    <span class="k">def</span> <span class="nf">check_naming_convention</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">hook_path</span><span class="p">:</span> <span class="n">Path</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">ValidationIssue</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 89</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Validate filename against naming convention&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 90</span><span class="cl">        <span class="n">issues</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln"> 91</span><span class="cl">        <span class="n">filename</span> <span class="o">=</span> <span class="n">hook_path</span><span class="o">.</span><span class="n">name</span>
</span></span><span class="line"><span class="ln"> 92</span><span class="cl">
</span></span><span class="line"><span class="ln"> 93</span><span class="cl">        <span class="k">if</span> <span class="n">_USE_RUST</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 94</span><span class="cl">            <span class="n">valid</span> <span class="o">=</span> <span class="n">_rs</span><span class="o">.</span><span class="n">is_valid_hook_name</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 95</span><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 96</span><span class="cl">            <span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln"> 97</span><span class="cl">            <span class="n">valid</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">(</span><span class="n">re</span><span class="o">.</span><span class="k">match</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 98</span><span class="cl">                <span class="sa">r</span><span class="s2">&#34;^[a-z0-9](/python-advanced/06-rust-extensions/case-studies/rust-regex/[a-z0-9\-_]*[a-z0-9])?\.py$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 99</span><span class="cl">                <span class="n">filename</span>
</span></span><span class="line"><span class="ln">100</span><span class="cl">            <span class="p">))</span>
</span></span><span class="line"><span class="ln">101</span><span class="cl">
</span></span><span class="line"><span class="ln">102</span><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">valid</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">103</span><span class="cl">            <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">104</span><span class="cl">                <span class="n">level</span><span class="o">=</span><span class="s2">&#34;warning&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">105</span><span class="cl">                <span class="n">message</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;Invalid filename: </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">106</span><span class="cl">                <span class="n">suggestion</span><span class="o">=</span><span class="s2">&#34;Use snake-case or kebab-case: check_permissions.py&#34;</span>
</span></span><span class="line"><span class="ln">107</span><span class="cl">            <span class="p">))</span>
</span></span><span class="line"><span class="ln">108</span><span class="cl">
</span></span><span class="line"><span class="ln">109</span><span class="cl">        <span class="k">return</span> <span class="n">issues</span>
</span></span><span class="line"><span class="ln">110</span><span class="cl">
</span></span><span class="line"><span class="ln">111</span><span class="cl">    <span class="k">def</span> <span class="nf">validate_hook</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">hook_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ValidationResult</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">112</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Validate a single hook file&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">113</span><span class="cl">        <span class="n">path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_resolve_path</span><span class="p">(</span><span class="n">hook_path</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">114</span><span class="cl">
</span></span><span class="line"><span class="ln">115</span><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">116</span><span class="cl">            <span class="k">return</span> <span class="n">ValidationResult</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">117</span><span class="cl">                <span class="n">hook_path</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">path</span><span class="p">),</span>
</span></span><span class="line"><span class="ln">118</span><span class="cl">                <span class="n">issues</span><span class="o">=</span><span class="p">[</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">119</span><span class="cl">                    <span class="n">level</span><span class="o">=</span><span class="s2">&#34;error&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">120</span><span class="cl">                    <span class="n">message</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;Hook file not found: </span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">121</span><span class="cl">                <span class="p">)]</span>
</span></span><span class="line"><span class="ln">122</span><span class="cl">            <span class="p">)</span>
</span></span><span class="line"><span class="ln">123</span><span class="cl">
</span></span><span class="line"><span class="ln">124</span><span class="cl">        <span class="n">content</span> <span class="o">=</span> <span class="n">path</span><span class="o">.</span><span class="n">read_text</span><span class="p">(</span><span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">125</span><span class="cl">        <span class="n">issues</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">126</span><span class="cl">        <span class="n">issues</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">check_naming_convention</span><span class="p">(</span><span class="n">path</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">127</span><span class="cl">        <span class="n">issues</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">check_lib_imports</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">path</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">128</span><span class="cl">
</span></span><span class="line"><span class="ln">129</span><span class="cl">        <span class="k">return</span> <span class="n">ValidationResult</span><span class="p">(</span><span class="n">hook_path</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">path</span><span class="p">),</span> <span class="n">issues</span><span class="o">=</span><span class="n">issues</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">130</span><span class="cl">
</span></span><span class="line"><span class="ln">131</span><span class="cl">    <span class="k">def</span> <span class="nf">validate_all_hooks</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">132</span><span class="cl">        <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">133</span><span class="cl">        <span class="n">hooks_dir</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="ln">134</span><span class="cl">    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">ValidationResult</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">135</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Validate all hooks with batch optimization&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">136</span><span class="cl">        <span class="k">if</span> <span class="n">hooks_dir</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">137</span><span class="cl">            <span class="n">hooks_dir</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">project_root</span> <span class="o">/</span> <span class="s2">&#34;.claude&#34;</span> <span class="o">/</span> <span class="s2">&#34;hooks&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">138</span><span class="cl">
</span></span><span class="line"><span class="ln">139</span><span class="cl">        <span class="n">hooks_path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_resolve_path</span><span class="p">(</span><span class="n">hooks_dir</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">140</span><span class="cl">        <span class="n">hook_files</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">hooks_path</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s2">&#34;*.py&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">141</span><span class="cl">
</span></span><span class="line"><span class="ln">142</span><span class="cl">        <span class="k">if</span> <span class="n">_USE_RUST</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">hook_files</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">143</span><span class="cl">            <span class="c1"># Use batch validation for multiple files</span>
</span></span><span class="line"><span class="ln">144</span><span class="cl">            <span class="n">files_content</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">145</span><span class="cl">                <span class="nb">str</span><span class="p">(</span><span class="n">f</span><span class="p">):</span> <span class="n">f</span><span class="o">.</span><span class="n">read_text</span><span class="p">(</span><span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">146</span><span class="cl">                <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">hook_files</span>
</span></span><span class="line"><span class="ln">147</span><span class="cl">                <span class="k">if</span> <span class="ow">not</span> <span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;_&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">148</span><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="ln">149</span><span class="cl">
</span></span><span class="line"><span class="ln">150</span><span class="cl">            <span class="n">batch_result</span> <span class="o">=</span> <span class="n">_rs</span><span class="o">.</span><span class="n">validate_batch</span><span class="p">(</span><span class="n">files_content</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">151</span><span class="cl">
</span></span><span class="line"><span class="ln">152</span><span class="cl">            <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">153</span><span class="cl">            <span class="k">for</span> <span class="n">path</span><span class="p">,</span> <span class="n">content</span> <span class="ow">in</span> <span class="n">files_content</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">154</span><span class="cl">                <span class="n">import_result</span> <span class="o">=</span> <span class="n">batch_result</span><span class="o">.</span><span class="n">results</span><span class="p">[</span><span class="n">path</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">155</span><span class="cl">                <span class="n">valid_name</span> <span class="o">=</span> <span class="n">batch_result</span><span class="o">.</span><span class="n">valid_names</span><span class="p">[</span><span class="n">path</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">156</span><span class="cl">
</span></span><span class="line"><span class="ln">157</span><span class="cl">                <span class="n">issues</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_import_result_to_issues</span><span class="p">(</span><span class="n">import_result</span><span class="p">,</span> <span class="n">valid_name</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">158</span><span class="cl">                <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationResult</span><span class="p">(</span><span class="n">hook_path</span><span class="o">=</span><span class="n">path</span><span class="p">,</span> <span class="n">issues</span><span class="o">=</span><span class="n">issues</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">159</span><span class="cl">
</span></span><span class="line"><span class="ln">160</span><span class="cl">            <span class="k">return</span> <span class="n">results</span>
</span></span><span class="line"><span class="ln">161</span><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">162</span><span class="cl">            <span class="c1"># Single file or no Rust: use standard validation</span>
</span></span><span class="line"><span class="ln">163</span><span class="cl">            <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">164</span><span class="cl">                <span class="bp">self</span><span class="o">.</span><span class="n">validate_hook</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">f</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">165</span><span class="cl">                <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">hook_files</span>
</span></span><span class="line"><span class="ln">166</span><span class="cl">                <span class="k">if</span> <span class="ow">not</span> <span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;_&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">167</span><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="ln">168</span><span class="cl">
</span></span><span class="line"><span class="ln">169</span><span class="cl">    <span class="k">def</span> <span class="nf">_resolve_path</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Path</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">170</span><span class="cl">        <span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">171</span><span class="cl">        <span class="k">return</span> <span class="n">p</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">is_absolute</span><span class="p">()</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">project_root</span> <span class="o">/</span> <span class="n">p</span>
</span></span><span class="line"><span class="ln">172</span><span class="cl">
</span></span><span class="line"><span class="ln">173</span><span class="cl">    <span class="k">def</span> <span class="nf">_import_result_to_issues</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">174</span><span class="cl">        <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">175</span><span class="cl">        <span class="n">result</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">176</span><span class="cl">        <span class="n">valid_name</span><span class="p">:</span> <span class="nb">bool</span>
</span></span><span class="line"><span class="ln">177</span><span class="cl">    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">ValidationIssue</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">178</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Convert Rust ImportCheckResult to list of issues&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">179</span><span class="cl">        <span class="n">issues</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">180</span><span class="cl">
</span></span><span class="line"><span class="ln">181</span><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">valid_name</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">182</span><span class="cl">            <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">183</span><span class="cl">                <span class="n">level</span><span class="o">=</span><span class="s2">&#34;warning&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">184</span><span class="cl">                <span class="n">message</span><span class="o">=</span><span class="s2">&#34;Invalid filename format&#34;</span>
</span></span><span class="line"><span class="ln">185</span><span class="cl">            <span class="p">))</span>
</span></span><span class="line"><span class="ln">186</span><span class="cl">
</span></span><span class="line"><span class="ln">187</span><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">result</span><span class="o">.</span><span class="n">has_hook_io</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">188</span><span class="cl">            <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">189</span><span class="cl">                <span class="n">level</span><span class="o">=</span><span class="s2">&#34;warning&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">190</span><span class="cl">                <span class="n">message</span><span class="o">=</span><span class="s2">&#34;Missing hook_io import&#34;</span>
</span></span><span class="line"><span class="ln">191</span><span class="cl">            <span class="p">))</span>
</span></span><span class="line"><span class="ln">192</span><span class="cl">
</span></span><span class="line"><span class="ln">193</span><span class="cl">        <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">has_bad_output</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">194</span><span class="cl">            <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">195</span><span class="cl">                <span class="n">level</span><span class="o">=</span><span class="s2">&#34;warning&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">196</span><span class="cl">                <span class="n">message</span><span class="o">=</span><span class="s2">&#34;Using deprecated output pattern&#34;</span>
</span></span><span class="line"><span class="ln">197</span><span class="cl">            <span class="p">))</span>
</span></span><span class="line"><span class="ln">198</span><span class="cl">
</span></span><span class="line"><span class="ln">199</span><span class="cl">        <span class="k">return</span> <span class="n">issues</span>
</span></span><span class="line"><span class="ln">200</span><span class="cl">
</span></span><span class="line"><span class="ln">201</span><span class="cl">    <span class="k">def</span> <span class="nf">_check_imports_python</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">202</span><span class="cl">        <span class="bp">self</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">203</span><span class="cl">        <span class="n">content</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">204</span><span class="cl">        <span class="n">hook_path</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">205</span><span class="cl">    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">ValidationIssue</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">206</span><span class="cl">        <span class="s2">&#34;&#34;&#34;Pure Python fallback for import checking&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">207</span><span class="cl">        <span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln">208</span><span class="cl">        <span class="n">issues</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">209</span><span class="cl">
</span></span><span class="line"><span class="ln">210</span><span class="cl">        <span class="n">hook_io_patterns</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">211</span><span class="cl">            <span class="sa">r</span><span class="s2">&#34;from\s+hook_io\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">212</span><span class="cl">            <span class="sa">r</span><span class="s2">&#34;from\s+lib\.hook_io\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">213</span><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="ln">214</span><span class="cl">
</span></span><span class="line"><span class="ln">215</span><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">hook_io_patterns</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">216</span><span class="cl">            <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ValidationIssue</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">217</span><span class="cl">                <span class="n">level</span><span class="o">=</span><span class="s2">&#34;warning&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">218</span><span class="cl">                <span class="n">message</span><span class="o">=</span><span class="s2">&#34;Missing hook_io import&#34;</span>
</span></span><span class="line"><span class="ln">219</span><span class="cl">            <span class="p">))</span>
</span></span><span class="line"><span class="ln">220</span><span class="cl">
</span></span><span class="line"><span class="ln">221</span><span class="cl">        <span class="k">return</span> <span class="n">issues</span></span></span></code></pre></div><h3 id="完整程式碼">完整程式碼</h3>
<p>以下是完整的 <code>src/lib.rs</code>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln">  1</span><span class="cl"><span class="sd">//! Hook Validator - Rust regex acceleration for Python hook validation
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="sd">//!
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="sd">//! This module provides pre-compiled regex patterns for validating
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="sd">//! Claude Code hook files, with significant performance improvements
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="sd">//! over pure Python regex.
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="sd"></span><span class="w">
</span></span></span><span class="line"><span class="ln">  7</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">once_cell</span>::<span class="n">sync</span>::<span class="n">Lazy</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">regex</span>::<span class="p">{</span><span class="n">Regex</span><span class="p">,</span><span class="w"> </span><span class="n">RegexSet</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 13</span><span class="cl"><span class="c1">// Pre-compiled Regex Patterns
</span></span></span><span class="line"><span class="ln"> 14</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 15</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="w"></span><span class="sd">/// Import patterns for hook_io module
</span></span></span><span class="line"><span class="ln"> 17</span><span class="cl"><span class="sd"></span><span class="k">static</span><span class="w"> </span><span class="no">HOOK_IO_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 18</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 19</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+hook_io\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+lib\.hook_io\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 21</span><span class="cl"><span class="w">    </span><span class="p">])</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 22</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid HOOK_IO_REGEX pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 23</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 24</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 25</span><span class="cl"><span class="w"></span><span class="sd">/// Import patterns for hook_logging module
</span></span></span><span class="line"><span class="ln"> 26</span><span class="cl"><span class="sd"></span><span class="k">static</span><span class="w"> </span><span class="no">HOOK_LOGGING_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 27</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+hook_logging\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+lib\.hook_logging\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="w">    </span><span class="p">])</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 31</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid HOOK_LOGGING_REGEX pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 32</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 33</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="w"></span><span class="sd">/// Import patterns for config_loader module
</span></span></span><span class="line"><span class="ln"> 35</span><span class="cl"><span class="sd"></span><span class="k">static</span><span class="w"> </span><span class="no">CONFIG_LOADER_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 36</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 37</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+config_loader\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 38</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+lib\.config_loader\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 39</span><span class="cl"><span class="w">    </span><span class="p">])</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid CONFIG_LOADER_REGEX pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 42</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 43</span><span class="cl"><span class="w"></span><span class="sd">/// Import patterns for git_utils module
</span></span></span><span class="line"><span class="ln"> 44</span><span class="cl"><span class="sd"></span><span class="k">static</span><span class="w"> </span><span class="no">GIT_UTILS_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 45</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 46</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+git_utils\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 47</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;from\s+lib\.git_utils\s+import&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 48</span><span class="cl"><span class="w">    </span><span class="p">])</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 49</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid GIT_UTILS_REGEX pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 50</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 52</span><span class="cl"><span class="w"></span><span class="sd">/// Recommended output function patterns
</span></span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="sd"></span><span class="k">static</span><span class="w"> </span><span class="no">OUTPUT_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 55</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;write_hook_output\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 56</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;create_pretooluse_output\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 57</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;create_posttooluse_output\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 58</span><span class="cl"><span class="w">    </span><span class="p">])</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 59</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid OUTPUT_REGEX pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 60</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 61</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 62</span><span class="cl"><span class="w"></span><span class="sd">/// Deprecated output patterns (should be avoided)
</span></span></span><span class="line"><span class="ln"> 63</span><span class="cl"><span class="sd"></span><span class="k">static</span><span class="w"> </span><span class="no">BAD_OUTPUT_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 64</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 65</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;print\s*\(\s*json\.dumps\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 66</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;sys\.stdout\.write\s*\(\s*json\.dumps\s*\(&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 67</span><span class="cl"><span class="w">    </span><span class="p">])</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 68</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid BAD_OUTPUT_REGEX pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 69</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 70</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 71</span><span class="cl"><span class="w"></span><span class="sd">/// Valid hook filename pattern (anchored)
</span></span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="sd"></span><span class="k">static</span><span class="w"> </span><span class="no">VALID_NAME_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 73</span><span class="cl"><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;^[a-z0-9](/python-advanced/06-rust-extensions/case-studies/rust-regex/[a-z0-9\-_]*[a-z0-9])?\.py$&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 74</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid VALID_NAME_REGEX pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 75</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 76</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 77</span><span class="cl"><span class="w"></span><span class="sd">/// JSON output detection patterns
</span></span></span><span class="line"><span class="ln"> 78</span><span class="cl"><span class="sd"></span><span class="k">static</span><span class="w"> </span><span class="no">JSON_OUTPUT_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 79</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 80</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;json\.dumps&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 81</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;write_hook_output&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 82</span><span class="cl"><span class="w">        </span><span class="sa">r</span><span class="s">&#34;create_.*_output&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 83</span><span class="cl"><span class="w">    </span><span class="p">])</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 84</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid JSON_OUTPUT_REGEX pattern&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 85</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 86</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 87</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 88</span><span class="cl"><span class="c1">// Result Types
</span></span></span><span class="line"><span class="ln"> 89</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln"> 90</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 91</span><span class="cl"><span class="w"></span><span class="sd">/// Result of checking import patterns in source code
</span></span></span><span class="line"><span class="ln"> 92</span><span class="cl"><span class="sd"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 93</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Clone, Debug)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 94</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">ImportCheckResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 95</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 96</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_hook_io</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 97</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 98</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_hook_logging</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 99</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">100</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_config_loader</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">101</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">102</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_git_utils</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">103</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">104</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_good_output</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">105</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">106</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_bad_output</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">107</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">108</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">has_json_output</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">109</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">110</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">111</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">112</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">ImportCheckResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">113</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">114</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">115</span><span class="cl"><span class="w">            </span><span class="s">&#34;ImportCheckResult(hook_io=</span><span class="si">{}</span><span class="s">, logging=</span><span class="si">{}</span><span class="s">, config=</span><span class="si">{}</span><span class="s">, git=</span><span class="si">{}</span><span class="s">, </span><span class="se">\</span><span class="s">
</span></span></span><span class="line"><span class="ln">116</span><span class="cl"><span class="s">             good_out=</span><span class="si">{}</span><span class="s">, bad_out=</span><span class="si">{}</span><span class="s">, json_out=</span><span class="si">{}</span><span class="s">)&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">117</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_hook_io</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">118</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_hook_logging</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">119</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_config_loader</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">120</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_git_utils</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">121</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_good_output</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">122</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_bad_output</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">123</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">has_json_output</span><span class="w">
</span></span></span><span class="line"><span class="ln">124</span><span class="cl"><span class="w">        </span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">125</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">126</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">127</span><span class="cl"><span class="w">    </span><span class="sd">/// Check if the hook uses recommended output patterns
</span></span></span><span class="line"><span class="ln">128</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">uses_recommended_output</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">129</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">has_good_output</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="o">!</span><span class="bp">self</span><span class="p">.</span><span class="n">has_bad_output</span><span class="w">
</span></span></span><span class="line"><span class="ln">130</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">131</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">132</span><span class="cl"><span class="w">    </span><span class="sd">/// Check if the hook has all required imports
</span></span></span><span class="line"><span class="ln">133</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">has_required_imports</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">134</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">has_hook_io</span><span class="w">
</span></span></span><span class="line"><span class="ln">135</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">136</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">137</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">138</span><span class="cl"><span class="w"></span><span class="sd">/// Batch validation result for multiple files
</span></span></span><span class="line"><span class="ln">139</span><span class="cl"><span class="sd"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln">140</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Clone, Debug)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">141</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">BatchValidationResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">142</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">143</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">results</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">ImportCheckResult</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">144</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">145</span><span class="cl"><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="n">valid_names</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">146</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">147</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">148</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">149</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">BatchValidationResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">150</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">151</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;BatchValidationResult(</span><span class="si">{}</span><span class="s"> files)&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">results</span><span class="p">.</span><span class="n">len</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">152</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">153</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">154</span><span class="cl"><span class="w">    </span><span class="sd">/// Get list of files missing hook_io import
</span></span></span><span class="line"><span class="ln">155</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">files_missing_hook_io</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">156</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">results</span><span class="w">
</span></span></span><span class="line"><span class="ln">157</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">158</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="o">!</span><span class="n">r</span><span class="p">.</span><span class="n">has_hook_io</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">159</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">160</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">161</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">162</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">163</span><span class="cl"><span class="w">    </span><span class="sd">/// Get list of files using bad output patterns
</span></span></span><span class="line"><span class="ln">164</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">files_with_bad_output</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">165</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">results</span><span class="w">
</span></span></span><span class="line"><span class="ln">166</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">167</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">has_bad_output</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">168</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">169</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">170</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">171</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">172</span><span class="cl"><span class="w">    </span><span class="sd">/// Get list of files with invalid names
</span></span></span><span class="line"><span class="ln">173</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">files_with_invalid_names</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">174</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">valid_names</span><span class="w">
</span></span></span><span class="line"><span class="ln">175</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">176</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">valid</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="o">!*</span><span class="n">valid</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">177</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">178</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">179</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">180</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">181</span><span class="cl"><span class="w">    </span><span class="sd">/// Get summary statistics
</span></span></span><span class="line"><span class="ln">182</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">summary</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">183</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">stats</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">184</span><span class="cl"><span class="w">        </span><span class="n">stats</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="s">&#34;total&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">results</span><span class="p">.</span><span class="n">len</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">185</span><span class="cl"><span class="w">        </span><span class="n">stats</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">186</span><span class="cl"><span class="w">            </span><span class="s">&#34;missing_hook_io&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">187</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">files_missing_hook_io</span><span class="p">().</span><span class="n">len</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">188</span><span class="cl"><span class="w">        </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">189</span><span class="cl"><span class="w">        </span><span class="n">stats</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">190</span><span class="cl"><span class="w">            </span><span class="s">&#34;bad_output&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">191</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">files_with_bad_output</span><span class="p">().</span><span class="n">len</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">192</span><span class="cl"><span class="w">        </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">193</span><span class="cl"><span class="w">        </span><span class="n">stats</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">194</span><span class="cl"><span class="w">            </span><span class="s">&#34;invalid_names&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">195</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">files_with_invalid_names</span><span class="p">().</span><span class="n">len</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">196</span><span class="cl"><span class="w">        </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">197</span><span class="cl"><span class="w">        </span><span class="n">stats</span><span class="w">
</span></span></span><span class="line"><span class="ln">198</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">199</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">200</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">201</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln">202</span><span class="cl"><span class="c1">// Public API Functions
</span></span></span><span class="line"><span class="ln">203</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln">204</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">205</span><span class="cl"><span class="w"></span><span class="sd">/// Check all import patterns in source code
</span></span></span><span class="line"><span class="ln">206</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">207</span><span class="cl"><span class="sd">/// This function performs all pattern checks in a single pass through
</span></span></span><span class="line"><span class="ln">208</span><span class="cl"><span class="sd">/// the content, making it much more efficient than individual checks.
</span></span></span><span class="line"><span class="ln">209</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">210</span><span class="cl"><span class="sd">/// # Arguments
</span></span></span><span class="line"><span class="ln">211</span><span class="cl"><span class="sd">/// * `content` - The source code content to check
</span></span></span><span class="line"><span class="ln">212</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">213</span><span class="cl"><span class="sd">/// # Returns
</span></span></span><span class="line"><span class="ln">214</span><span class="cl"><span class="sd">/// * `ImportCheckResult` - Results of all pattern checks
</span></span></span><span class="line"><span class="ln">215</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">216</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">check_imports</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">ImportCheckResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">217</span><span class="cl"><span class="w">    </span><span class="n">ImportCheckResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">218</span><span class="cl"><span class="w">        </span><span class="n">has_hook_io</span>: <span class="nc">HOOK_IO_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">219</span><span class="cl"><span class="w">        </span><span class="n">has_hook_logging</span>: <span class="nc">HOOK_LOGGING_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">220</span><span class="cl"><span class="w">        </span><span class="n">has_config_loader</span>: <span class="nc">CONFIG_LOADER_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">221</span><span class="cl"><span class="w">        </span><span class="n">has_git_utils</span>: <span class="nc">GIT_UTILS_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">222</span><span class="cl"><span class="w">        </span><span class="n">has_good_output</span>: <span class="nc">OUTPUT_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">223</span><span class="cl"><span class="w">        </span><span class="n">has_bad_output</span>: <span class="nc">BAD_OUTPUT_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">224</span><span class="cl"><span class="w">        </span><span class="n">has_json_output</span>: <span class="nc">JSON_OUTPUT_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">225</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">226</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">227</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">228</span><span class="cl"><span class="w"></span><span class="sd">/// Validate filename against naming convention
</span></span></span><span class="line"><span class="ln">229</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">230</span><span class="cl"><span class="sd">/// Valid names must:
</span></span></span><span class="line"><span class="ln">231</span><span class="cl"><span class="sd">/// - Start and end with lowercase alphanumeric
</span></span></span><span class="line"><span class="ln">232</span><span class="cl"><span class="sd">/// - Contain only lowercase letters, numbers, hyphens, underscores
</span></span></span><span class="line"><span class="ln">233</span><span class="cl"><span class="sd">/// - Have .py extension
</span></span></span><span class="line"><span class="ln">234</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">235</span><span class="cl"><span class="sd">/// # Arguments
</span></span></span><span class="line"><span class="ln">236</span><span class="cl"><span class="sd">/// * `filename` - The filename to validate (just the name, not full path)
</span></span></span><span class="line"><span class="ln">237</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">238</span><span class="cl"><span class="sd">/// # Returns
</span></span></span><span class="line"><span class="ln">239</span><span class="cl"><span class="sd">/// * `bool` - True if the filename is valid
</span></span></span><span class="line"><span class="ln">240</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">241</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">is_valid_hook_name</span><span class="p">(</span><span class="n">filename</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">242</span><span class="cl"><span class="w">    </span><span class="no">VALID_NAME_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">243</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">244</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">245</span><span class="cl"><span class="w"></span><span class="sd">/// Get indices of matched patterns in a pattern group
</span></span></span><span class="line"><span class="ln">246</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">247</span><span class="cl"><span class="sd">/// Useful for detailed reporting of which specific patterns matched.
</span></span></span><span class="line"><span class="ln">248</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">249</span><span class="cl"><span class="sd">/// # Arguments
</span></span></span><span class="line"><span class="ln">250</span><span class="cl"><span class="sd">/// * `content` - The source code content to check
</span></span></span><span class="line"><span class="ln">251</span><span class="cl"><span class="sd">/// * `pattern_group` - One of: &#34;hook_io&#34;, &#34;hook_logging&#34;, &#34;config_loader&#34;,
</span></span></span><span class="line"><span class="ln">252</span><span class="cl"><span class="sd">///                     &#34;git_utils&#34;, &#34;output&#34;, &#34;bad_output&#34;, &#34;json_output&#34;
</span></span></span><span class="line"><span class="ln">253</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">254</span><span class="cl"><span class="sd">/// # Returns
</span></span></span><span class="line"><span class="ln">255</span><span class="cl"><span class="sd">/// * `Vec&lt;usize&gt;` - Indices of patterns that matched
</span></span></span><span class="line"><span class="ln">256</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">257</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">get_matched_patterns</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">pattern_group</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">258</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">regex_set</span>: <span class="kp">&amp;</span><span class="nc">RegexSet</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">pattern_group</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">259</span><span class="cl"><span class="w">        </span><span class="s">&#34;hook_io&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;</span><span class="no">HOOK_IO_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">260</span><span class="cl"><span class="w">        </span><span class="s">&#34;hook_logging&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;</span><span class="no">HOOK_LOGGING_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">261</span><span class="cl"><span class="w">        </span><span class="s">&#34;config_loader&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;</span><span class="no">CONFIG_LOADER_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">262</span><span class="cl"><span class="w">        </span><span class="s">&#34;git_utils&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;</span><span class="no">GIT_UTILS_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">263</span><span class="cl"><span class="w">        </span><span class="s">&#34;output&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;</span><span class="no">OUTPUT_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">264</span><span class="cl"><span class="w">        </span><span class="s">&#34;bad_output&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;</span><span class="no">BAD_OUTPUT_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">265</span><span class="cl"><span class="w">        </span><span class="s">&#34;json_output&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="o">&amp;</span><span class="no">JSON_OUTPUT_REGEX</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">266</span><span class="cl"><span class="w">        </span><span class="n">_</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[],</span><span class="w">
</span></span></span><span class="line"><span class="ln">267</span><span class="cl"><span class="w">    </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln">268</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">269</span><span class="cl"><span class="w">    </span><span class="n">regex_set</span><span class="p">.</span><span class="n">matches</span><span class="p">(</span><span class="n">content</span><span class="p">).</span><span class="n">iter</span><span class="p">().</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">270</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">271</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">272</span><span class="cl"><span class="w"></span><span class="sd">/// Validate multiple files in a single batch operation
</span></span></span><span class="line"><span class="ln">273</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">274</span><span class="cl"><span class="sd">/// This is significantly more efficient than validating files one by one,
</span></span></span><span class="line"><span class="ln">275</span><span class="cl"><span class="sd">/// especially when dealing with many files.
</span></span></span><span class="line"><span class="ln">276</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">277</span><span class="cl"><span class="sd">/// # Arguments
</span></span></span><span class="line"><span class="ln">278</span><span class="cl"><span class="sd">/// * `files` - HashMap of file paths to their contents
</span></span></span><span class="line"><span class="ln">279</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">280</span><span class="cl"><span class="sd">/// # Returns
</span></span></span><span class="line"><span class="ln">281</span><span class="cl"><span class="sd">/// * `BatchValidationResult` - Combined results for all files
</span></span></span><span class="line"><span class="ln">282</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">283</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">validate_batch</span><span class="p">(</span><span class="n">files</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">String</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">BatchValidationResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">284</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">results</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">ImportCheckResult</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files</span><span class="w">
</span></span></span><span class="line"><span class="ln">285</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">286</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">content</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w"> </span><span class="n">check_imports</span><span class="p">(</span><span class="n">content</span><span class="p">)))</span><span class="w">
</span></span></span><span class="line"><span class="ln">287</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">288</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">289</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">valid_names</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files</span><span class="w">
</span></span></span><span class="line"><span class="ln">290</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">keys</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">291</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">path</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">292</span><span class="cl"><span class="w">            </span><span class="c1">// Extract filename from path
</span></span></span><span class="line"><span class="ln">293</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">filename</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">path</span><span class="p">.</span><span class="n">rsplit</span><span class="p">(</span><span class="sc">&#39;/&#39;</span><span class="p">).</span><span class="n">next</span><span class="p">().</span><span class="n">unwrap_or</span><span class="p">(</span><span class="n">path</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">294</span><span class="cl"><span class="w">            </span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w"> </span><span class="n">is_valid_hook_name</span><span class="p">(</span><span class="n">filename</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">295</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">296</span><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">297</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">298</span><span class="cl"><span class="w">    </span><span class="n">BatchValidationResult</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">299</span><span class="cl"><span class="w">        </span><span class="n">results</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">300</span><span class="cl"><span class="w">        </span><span class="n">valid_names</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">301</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">302</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">303</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">304</span><span class="cl"><span class="w"></span><span class="sd">/// Check if content contains specific import pattern (simple check)
</span></span></span><span class="line"><span class="ln">305</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">306</span><span class="cl"><span class="sd">/// # Arguments
</span></span></span><span class="line"><span class="ln">307</span><span class="cl"><span class="sd">/// * `content` - The source code to check
</span></span></span><span class="line"><span class="ln">308</span><span class="cl"><span class="sd">/// * `module_name` - The module to check for: &#34;hook_io&#34;, &#34;hook_logging&#34;, etc.
</span></span></span><span class="line"><span class="ln">309</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">310</span><span class="cl"><span class="sd">/// # Returns
</span></span></span><span class="line"><span class="ln">311</span><span class="cl"><span class="sd">/// * `bool` - True if the import pattern is found
</span></span></span><span class="line"><span class="ln">312</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">313</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">has_import</span><span class="p">(</span><span class="n">content</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">module_name</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">314</span><span class="cl"><span class="w">    </span><span class="k">match</span><span class="w"> </span><span class="n">module_name</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">315</span><span class="cl"><span class="w">        </span><span class="s">&#34;hook_io&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="no">HOOK_IO_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">316</span><span class="cl"><span class="w">        </span><span class="s">&#34;hook_logging&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="no">HOOK_LOGGING_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">317</span><span class="cl"><span class="w">        </span><span class="s">&#34;config_loader&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="no">CONFIG_LOADER_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">318</span><span class="cl"><span class="w">        </span><span class="s">&#34;git_utils&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="no">GIT_UTILS_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">content</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">319</span><span class="cl"><span class="w">        </span><span class="n">_</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">320</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">321</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">322</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">323</span><span class="cl"><span class="w"></span><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln">324</span><span class="cl"><span class="c1">// Python Module Definition
</span></span></span><span class="line"><span class="ln">325</span><span class="cl"><span class="c1">// ============================================================================
</span></span></span><span class="line"><span class="ln">326</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">327</span><span class="cl"><span class="w"></span><span class="sd">/// Rust-accelerated hook validator with pre-compiled regex patterns
</span></span></span><span class="line"><span class="ln">328</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">329</span><span class="cl"><span class="sd">/// This module provides significant performance improvements over pure Python
</span></span></span><span class="line"><span class="ln">330</span><span class="cl"><span class="sd">/// regex for validating Claude Code hook files. Key features:
</span></span></span><span class="line"><span class="ln">331</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">332</span><span class="cl"><span class="sd">/// - Pre-compiled regex patterns using once_cell
</span></span></span><span class="line"><span class="ln">333</span><span class="cl"><span class="sd">/// - RegexSet for efficient multi-pattern matching
</span></span></span><span class="line"><span class="ln">334</span><span class="cl"><span class="sd">/// - Batch validation API for multiple files
</span></span></span><span class="line"><span class="ln">335</span><span class="cl"><span class="sd">/// - Guaranteed linear time complexity (DFA engine)
</span></span></span><span class="line"><span class="ln">336</span><span class="cl"><span class="sd"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">337</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">hook_validator_rs</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">338</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">check_imports</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">339</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">is_valid_hook_name</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">340</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">get_matched_patterns</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">341</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">validate_batch</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">342</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">has_import</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">343</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">ImportCheckResult</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">344</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">BatchValidationResult</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">345</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">346</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="建置與測試">建置與測試</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># Build the extension</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">maturin develop --release
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># Run tests</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">python -c <span class="s2">&#34;
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="s2">import hook_validator_rs as rs
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="s2"># Test basic import checking
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="s2">content = &#39;&#39;&#39;
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="s2">from hook_io import read_hook_input, write_hook_output
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="s2">from hook_logging import setup_hook_logging
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="s2">&#39;&#39;&#39;
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="s2">result = rs.check_imports(content)
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="s2">print(f&#39;Import check: {result}&#39;)
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="s2">print(f&#39;Has hook_io: {result.has_hook_io}&#39;)
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="s2">print(f&#39;Uses recommended output: {result.uses_recommended_output()}&#39;)
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="s2"># Test filename validation
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="s2">print(f&#39;Valid name \&#34;check-permissions.py\&#34;: {rs.is_valid_hook_name(\&#34;check-permissions.py\&#34;)}&#39;)
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="s2">print(f&#39;Valid name \&#34;BadName.py\&#34;: {rs.is_valid_hook_name(\&#34;BadName.py\&#34;)}&#39;)
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="s2">&#34;</span></span></span></code></pre></div><h3 id="效能比較">效能比較</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">  1</span><span class="cl"><span class="s2">&#34;&#34;&#34;Performance comparison: Python re vs Rust regex&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">  2</span><span class="cl">
</span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Callable</span>
</span></span><span class="line"><span class="ln">  6</span><span class="cl">
</span></span><span class="line"><span class="ln">  7</span><span class="cl"><span class="k">def</span> <span class="nf">benchmark</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">func</span><span class="p">:</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">iterations</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">10000</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">  8</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Run benchmark and return average time in microseconds&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">  9</span><span class="cl">    <span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 10</span><span class="cl">    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">iterations</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 11</span><span class="cl">        <span class="n">func</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 12</span><span class="cl">    <span class="n">elapsed</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span>
</span></span><span class="line"><span class="ln"> 13</span><span class="cl">    <span class="n">avg_us</span> <span class="o">=</span> <span class="p">(</span><span class="n">elapsed</span> <span class="o">/</span> <span class="n">iterations</span><span class="p">)</span> <span class="o">*</span> <span class="mi">1_000_000</span>
</span></span><span class="line"><span class="ln"> 14</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">avg_us</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> us/iteration (</span><span class="si">{</span><span class="n">iterations</span><span class="si">}</span><span class="s2"> iterations)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 15</span><span class="cl">    <span class="k">return</span> <span class="n">avg_us</span>
</span></span><span class="line"><span class="ln"> 16</span><span class="cl">
</span></span><span class="line"><span class="ln"> 17</span><span class="cl"><span class="c1"># Test content (typical hook file)</span>
</span></span><span class="line"><span class="ln"> 18</span><span class="cl"><span class="n">TEST_CONTENT</span> <span class="o">=</span> <span class="s1">&#39;&#39;&#39;
</span></span></span><span class="line"><span class="ln"> 19</span><span class="cl"><span class="s1">#!/usr/bin/env python3
</span></span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="s1">&#34;&#34;&#34;Example hook for testing performance&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 21</span><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="ln"> 22</span><span class="cl"><span class="s1">import json
</span></span></span><span class="line"><span class="ln"> 23</span><span class="cl"><span class="s1">import sys
</span></span></span><span class="line"><span class="ln"> 24</span><span class="cl"><span class="s1">from pathlib import Path
</span></span></span><span class="line"><span class="ln"> 25</span><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="ln"> 26</span><span class="cl"><span class="s1">from hook_io import read_hook_input, write_hook_output
</span></span></span><span class="line"><span class="ln"> 27</span><span class="cl"><span class="s1">from hook_logging import setup_hook_logging
</span></span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="s1">from config_loader import load_config
</span></span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="s1">def main():
</span></span></span><span class="line"><span class="ln"> 31</span><span class="cl"><span class="s1">    logger = setup_hook_logging(&#34;example-hook&#34;)
</span></span></span><span class="line"><span class="ln"> 32</span><span class="cl"><span class="s1">    hook_input = read_hook_input()
</span></span></span><span class="line"><span class="ln"> 33</span><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="s1">    # Process input
</span></span></span><span class="line"><span class="ln"> 35</span><span class="cl"><span class="s1">    result = {&#34;decision&#34;: &#34;approve&#34;}
</span></span></span><span class="line"><span class="ln"> 36</span><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="ln"> 37</span><span class="cl"><span class="s1">    write_hook_output(result)
</span></span></span><span class="line"><span class="ln"> 38</span><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="ln"> 39</span><span class="cl"><span class="s1">if __name__ == &#34;__main__&#34;:
</span></span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="s1">    main()
</span></span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="s1">&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="ln"> 42</span><span class="cl">
</span></span><span class="line"><span class="ln"> 43</span><span class="cl"><span class="c1"># Python patterns</span>
</span></span><span class="line"><span class="ln"> 44</span><span class="cl"><span class="n">HOOK_IO_PATTERNS_PY</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 45</span><span class="cl">    <span class="sa">r</span><span class="s2">&#34;from\s+hook_io\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 46</span><span class="cl">    <span class="sa">r</span><span class="s2">&#34;from\s+lib\.hook_io\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 47</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 48</span><span class="cl"><span class="n">HOOK_LOGGING_PATTERNS_PY</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 49</span><span class="cl">    <span class="sa">r</span><span class="s2">&#34;from\s+hook_logging\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 50</span><span class="cl">    <span class="sa">r</span><span class="s2">&#34;from\s+lib\.hook_logging\s+import&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 52</span><span class="cl">
</span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="k">def</span> <span class="nf">python_check</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 54</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Pure Python regex check&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 55</span><span class="cl">    <span class="n">has_hook_io</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 56</span><span class="cl">        <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">TEST_CONTENT</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">HOOK_IO_PATTERNS_PY</span>
</span></span><span class="line"><span class="ln"> 57</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln"> 58</span><span class="cl">    <span class="n">has_logging</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span>
</span></span><span class="line"><span class="ln"> 59</span><span class="cl">        <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">TEST_CONTENT</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">HOOK_LOGGING_PATTERNS_PY</span>
</span></span><span class="line"><span class="ln"> 60</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln"> 61</span><span class="cl">    <span class="k">return</span> <span class="n">has_hook_io</span><span class="p">,</span> <span class="n">has_logging</span>
</span></span><span class="line"><span class="ln"> 62</span><span class="cl">
</span></span><span class="line"><span class="ln"> 63</span><span class="cl"><span class="k">def</span> <span class="nf">python_check_compiled</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 64</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Python regex with pre-compiled patterns&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 65</span><span class="cl">    <span class="k">global</span> <span class="n">_compiled_hook_io</span><span class="p">,</span> <span class="n">_compiled_logging</span>
</span></span><span class="line"><span class="ln"> 66</span><span class="cl">    <span class="n">has_hook_io</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">TEST_CONTENT</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">_compiled_hook_io</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 67</span><span class="cl">    <span class="n">has_logging</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">TEST_CONTENT</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">_compiled_logging</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 68</span><span class="cl">    <span class="k">return</span> <span class="n">has_hook_io</span><span class="p">,</span> <span class="n">has_logging</span>
</span></span><span class="line"><span class="ln"> 69</span><span class="cl">
</span></span><span class="line"><span class="ln"> 70</span><span class="cl"><span class="c1"># Pre-compile Python patterns</span>
</span></span><span class="line"><span class="ln"> 71</span><span class="cl"><span class="n">_compiled_hook_io</span> <span class="o">=</span> <span class="p">[</span><span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">HOOK_IO_PATTERNS_PY</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="n">_compiled_logging</span> <span class="o">=</span> <span class="p">[</span><span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">HOOK_LOGGING_PATTERNS_PY</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 73</span><span class="cl">
</span></span><span class="line"><span class="ln"> 74</span><span class="cl"><span class="k">def</span> <span class="nf">rust_check</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 75</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Rust regex check&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 76</span><span class="cl">    <span class="kn">import</span> <span class="nn">hook_validator_rs</span> <span class="k">as</span> <span class="nn">rs</span>
</span></span><span class="line"><span class="ln"> 77</span><span class="cl">    <span class="n">result</span> <span class="o">=</span> <span class="n">rs</span><span class="o">.</span><span class="n">check_imports</span><span class="p">(</span><span class="n">TEST_CONTENT</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 78</span><span class="cl">    <span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">has_hook_io</span><span class="p">,</span> <span class="n">result</span><span class="o">.</span><span class="n">has_hook_logging</span>
</span></span><span class="line"><span class="ln"> 79</span><span class="cl">
</span></span><span class="line"><span class="ln"> 80</span><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 81</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 82</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Performance Comparison: Python re vs Rust regex&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 83</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 84</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Content size: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">TEST_CONTENT</span><span class="p">)</span><span class="si">}</span><span class="s2"> bytes</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 85</span><span class="cl">
</span></span><span class="line"><span class="ln"> 86</span><span class="cl">    <span class="c1"># Warm up</span>
</span></span><span class="line"><span class="ln"> 87</span><span class="cl">    <span class="n">python_check</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 88</span><span class="cl">    <span class="n">python_check_compiled</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 89</span><span class="cl">    <span class="n">rust_check</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 90</span><span class="cl">
</span></span><span class="line"><span class="ln"> 91</span><span class="cl">    <span class="c1"># Benchmark</span>
</span></span><span class="line"><span class="ln"> 92</span><span class="cl">    <span class="n">py_time</span> <span class="o">=</span> <span class="n">benchmark</span><span class="p">(</span><span class="s2">&#34;Python re (uncompiled)&#34;</span><span class="p">,</span> <span class="n">python_check</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 93</span><span class="cl">    <span class="n">py_compiled_time</span> <span class="o">=</span> <span class="n">benchmark</span><span class="p">(</span><span class="s2">&#34;Python re (compiled)&#34;</span><span class="p">,</span> <span class="n">python_check_compiled</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 94</span><span class="cl">    <span class="n">rust_time</span> <span class="o">=</span> <span class="n">benchmark</span><span class="p">(</span><span class="s2">&#34;Rust regex&#34;</span><span class="p">,</span> <span class="n">rust_check</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 95</span><span class="cl">
</span></span><span class="line"><span class="ln"> 96</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span> <span class="o">+</span> <span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 97</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Results Summary&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 98</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 99</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Python uncompiled: </span><span class="si">{</span><span class="n">py_time</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> us&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">100</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Python compiled:   </span><span class="si">{</span><span class="n">py_compiled_time</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> us&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">101</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Rust regex:        </span><span class="si">{</span><span class="n">rust_time</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> us&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">102</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">Speedup vs uncompiled: </span><span class="si">{</span><span class="n">py_time</span> <span class="o">/</span> <span class="n">rust_time</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2">x&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">103</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Speedup vs compiled:   </span><span class="si">{</span><span class="n">py_compiled_time</span> <span class="o">/</span> <span class="n">rust_time</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2">x&#34;</span><span class="p">)</span></span></span></code></pre></div><p>典型結果：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">============================================================
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">Performance Comparison: Python re vs Rust regex
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">============================================================
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Content size: 512 bytes
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Python re (uncompiled): 12.45 us/iteration (10000 iterations)
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">Python re (compiled):    4.32 us/iteration (10000 iterations)
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">Rust regex:              0.89 us/iteration (10000 iterations)
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">============================================================
</span></span><span class="line"><span class="ln">11</span><span class="cl">Results Summary
</span></span><span class="line"><span class="ln">12</span><span class="cl">============================================================
</span></span><span class="line"><span class="ln">13</span><span class="cl">Python uncompiled: 12.45 us
</span></span><span class="line"><span class="ln">14</span><span class="cl">Python compiled:    4.32 us
</span></span><span class="line"><span class="ln">15</span><span class="cl">Rust regex:         0.89 us
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">Speedup vs uncompiled: 14.0x
</span></span><span class="line"><span class="ln">18</span><span class="cl">Speedup vs compiled:   4.9x</span></span></code></pre></div><h4 id="病態輸入效能比較">病態輸入效能比較</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="s2">&#34;&#34;&#34;Pathological input benchmark - demonstrating DFA vs backtracking&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">def</span> <span class="nf">test_catastrophic_backtracking</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="s2">    Test pattern that causes catastrophic backtracking in NFA engines
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="s2">    Pattern: (a+)+b
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="s2">    Input: &#34;aaa...a&#34; (no &#39;b&#39; at end)
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="s2">    Python re: O(2^n) time complexity
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="s2">    Rust regex: O(n) time complexity (DFA engine)
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">pattern</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">&#34;(a+)+b&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Catastrophic Backtracking Test&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Pattern: (a+)+b&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;-&#34;</span> <span class="o">*</span> <span class="mi">50</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">15</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">22</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">25</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="n">text</span> <span class="o">=</span> <span class="s2">&#34;a&#34;</span> <span class="o">*</span> <span class="n">n</span> <span class="o">+</span> <span class="s2">&#34;c&#34;</span>  <span class="c1"># No match - triggers backtracking</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl">        <span class="c1"># Python test</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">        <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">            <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">        <span class="k">except</span> <span class="ne">TimeoutError</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">            <span class="n">py_time</span> <span class="o">=</span> <span class="s2">&#34;&gt;5s (timeout)&#34;</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">            <span class="n">py_time</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span><span class="o">*</span><span class="mi">1000</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">ms&#34;</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="c1"># Note: Rust regex doesn&#39;t support backreferences,</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">        <span class="c1"># so (a+)+b is rewritten as a+b internally</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">        <span class="c1"># This demonstrates why Rust regex is safe from this attack</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">
</span></span><span class="line"><span class="ln">38</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;n=</span><span class="si">{</span><span class="n">n</span><span class="si">:</span><span class="s2">2d</span><span class="si">}</span><span class="s2">: Python=</span><span class="si">{</span><span class="n">py_time</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="k">def</span> <span class="nf">test_regex_dos</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="s2">    Test ReDoS (Regular Expression Denial of Service) patterns
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl">    <span class="c1"># Common ReDoS patterns</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">    <span class="n">redos_patterns</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">        <span class="p">(</span><span class="sa">r</span><span class="s2">&#34;(a+)+$&#34;</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span> <span class="o">*</span> <span class="mi">20</span> <span class="o">+</span> <span class="s2">&#34;!&#34;</span><span class="p">),</span>          <span class="c1"># Nested quantifiers</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">        <span class="p">(</span><span class="sa">r</span><span class="s2">&#34;(a|aa)+$&#34;</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span> <span class="o">*</span> <span class="mi">20</span> <span class="o">+</span> <span class="s2">&#34;!&#34;</span><span class="p">),</span>        <span class="c1"># Overlapping alternatives</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">        <span class="p">(</span><span class="sa">r</span><span class="s2">&#34;(.*a)</span><span class="si">{10}</span><span class="s2">$&#34;</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">+</span> <span class="s2">&#34;!&#34;</span><span class="p">),</span>      <span class="c1"># Repeated wildcards</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl">
</span></span><span class="line"><span class="ln">51</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">ReDoS Pattern Tests&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;-&#34;</span> <span class="o">*</span> <span class="mi">50</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl">
</span></span><span class="line"><span class="ln">54</span><span class="cl">    <span class="k">for</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">text</span> <span class="ow">in</span> <span class="n">redos_patterns</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl">        <span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl">        <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl">        <span class="n">elapsed</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span>
</span></span><span class="line"><span class="ln">58</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Pattern: </span><span class="si">{</span><span class="n">pattern</span><span class="si">:</span><span class="s2">20s</span><span class="si">}</span><span class="s2"> Time: </span><span class="si">{</span><span class="n">elapsed</span><span class="o">*</span><span class="mi">1000</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">ms&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">59</span><span class="cl">
</span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">61</span><span class="cl">    <span class="n">test_catastrophic_backtracking</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">62</span><span class="cl">    <span class="n">test_regex_dos</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">63</span><span class="cl">
</span></span><span class="line"><span class="ln">64</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span> <span class="o">+</span> <span class="s2">&#34;=&#34;</span> <span class="o">*</span> <span class="mi">50</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">65</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Note: Rust regex crate uses DFA/hybrid engine&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">66</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;that guarantees O(n) time complexity for all inputs.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">67</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;It does NOT support backreferences, which prevents&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">68</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;catastrophic backtracking by design.&#34;</span><span class="p">)</span></span></span></code></pre></div><h2 id="設計權衡">設計權衡</h2>
<table>
  <thead>
      <tr>
          <th>面向</th>
          <th>Python re</th>
          <th>Rust regex</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>引擎類型</strong></td>
          <td>NFA with backtracking</td>
          <td>DFA/混合引擎</td>
      </tr>
      <tr>
          <td><strong>時間複雜度</strong></td>
          <td>最壞 O(2^n)</td>
          <td>保證 O(n)</td>
      </tr>
      <tr>
          <td><strong>功能完整性</strong></td>
          <td>完整（lookahead、backreference）</td>
          <td>部分限制（無 backreference）</td>
      </tr>
      <tr>
          <td><strong>整合難度</strong></td>
          <td>無（內建）</td>
          <td>需要 FFI（PyO3 + Maturin）</td>
      </tr>
      <tr>
          <td><strong>除錯便利</strong></td>
          <td>Python 原生</td>
          <td>需要 Rust 工具鏈</td>
      </tr>
      <tr>
          <td><strong>記憶體安全</strong></td>
          <td>GC 管理</td>
          <td>編譯時保證</td>
      </tr>
      <tr>
          <td><strong>多執行緒</strong></td>
          <td>受 GIL 限制</td>
          <td>完全平行化</td>
      </tr>
      <tr>
          <td><strong>SIMD 加速</strong></td>
          <td>無</td>
          <td>自動啟用</td>
      </tr>
  </tbody>
</table>
<h3 id="rust-regex-不支援的功能">Rust regex 不支援的功能</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// These patterns will fail to compile in Rust regex:
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="c1">// 1. Backreferences
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1">// r&#34;(\w+)\s+\1&#34;  // ERROR: backreference not supported
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="c1">// 2. Lookahead/Lookbehind
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1">// r&#34;(?=foo)&#34;    // ERROR: lookahead not supported
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1">// r&#34;(?&lt;=foo)&#34;   // ERROR: lookbehind not supported
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="c1">// 3. Atomic groups
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1">// r&#34;(?&gt;foo)&#34;    // ERROR: atomic groups not supported
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w"></span><span class="c1">// Workaround: Use regex-fancy crate for these features
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1">// (with performance trade-offs)
</span></span></span></code></pre></div><h2 id="什麼時候該用-rust-regex">什麼時候該用 Rust regex？</h2>
<h3 id="適合使用">適合使用</h3>
<ul>
<li><strong>大量文字需要驗證</strong>：日誌分析、程式碼審查、批次處理</li>
<li><strong>正則表達式可能有病態輸入</strong>：用戶提供的輸入、不可信來源</li>
<li><strong>需要保證線性時間</strong>：安全性要求、SLA 保證</li>
<li><strong>高併發場景</strong>：多執行緒處理、Web 服務</li>
<li><strong>效能關鍵路徑</strong>：CI/CD pipeline、即時驗證</li>
</ul>
<h3 id="不建議使用">不建議使用</h3>
<ul>
<li><strong>需要 lookahead/lookbehind</strong>：複雜的文字邊界檢查</li>
<li><strong>需要 backreference</strong>：重複單詞檢測、HTML 標籤匹配</li>
<li><strong>驗證次數很少</strong>：一次性腳本、開發階段</li>
<li><strong>模式簡單</strong>：固定字串、簡單前綴/後綴檢查</li>
<li><strong>團隊不熟悉 Rust</strong>：維護成本可能超過效能收益</li>
</ul>
<h2 id="練習">練習</h2>
<h3 id="1-基礎練習email-驗證">1. 基礎練習：Email 驗證</h3>
<p>用 Rust regex 實作 email 地址驗證：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// Exercise: Implement email validation
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">once_cell</span>::<span class="n">sync</span>::<span class="n">Lazy</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">regex</span>::<span class="n">Regex</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">EMAIL_REGEX</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">Regex</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="c1">// TODO: Implement email pattern
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// Requirements:
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// - Local part: alphanumeric + dots + underscores + hyphens
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// - @ symbol
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// - Domain: alphanumeric + dots + hyphens
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// - TLD: 2-6 alphabetic characters
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="sa">r</span><span class="s">&#34;TODO&#34;</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid email regex&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">is_valid_email</span><span class="p">(</span><span class="n">email</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">    </span><span class="no">EMAIL_REGEX</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="n">email</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w"></span><span class="c1">// Test cases:
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c1">// is_valid_email(&#34;user@example.com&#34;) -&gt; true
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1">// is_valid_email(&#34;user.name+tag@example.co.uk&#34;) -&gt; true
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1">// is_valid_email(&#34;invalid@&#34;) -&gt; false
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1">// is_valid_email(&#34;@example.com&#34;) -&gt; false
</span></span></span></code></pre></div><h3 id="2-進階練習regexset-批次匹配">2. 進階練習：RegexSet 批次匹配</h3>
<p>實作一個程式語言檢測器，判斷程式碼片段是哪種語言：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// Exercise: Language detection using RegexSet
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">once_cell</span>::<span class="n">sync</span>::<span class="n">Lazy</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">regex</span>::<span class="n">RegexSet</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">LANGUAGE_PATTERNS</span>: <span class="nc">Lazy</span><span class="o">&lt;</span><span class="n">RegexSet</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Lazy</span>::<span class="n">new</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="n">RegexSet</span>::<span class="n">new</span><span class="p">([</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">        </span><span class="c1">// TODO: Add patterns for different languages
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="c1">// 0: Python (def, import, from ... import)
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="c1">// 1: JavaScript (const, let, =&gt;)
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="c1">// 2: Rust (fn, let mut, impl)
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="c1">// 3: Go (func, package, import)
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="p">]).</span><span class="n">expect</span><span class="p">(</span><span class="s">&#34;Invalid language patterns&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="k">static</span><span class="w"> </span><span class="no">LANGUAGE_NAMES</span>: <span class="p">[</span><span class="o">&amp;</span><span class="kt">str</span><span class="p">;</span><span class="w"> </span><span class="mi">4</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s">&#34;Python&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;JavaScript&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;Rust&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;Go&#34;</span><span class="p">];</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">detect_languages</span><span class="p">(</span><span class="n">code</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">    </span><span class="c1">// TODO: Return list of detected languages
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// Hint: Use LANGUAGE_PATTERNS.matches(code)
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="fm">vec!</span><span class="p">[]</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w"></span><span class="c1">// Test case:
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="c1">// detect_languages(&#34;def hello():\n    print(&#39;Hi&#39;)&#34;) -&gt; [&#34;Python&#34;]
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="c1">// detect_languages(&#34;const x = () =&gt; {}&#34;) -&gt; [&#34;JavaScript&#34;]
</span></span></span></code></pre></div><h3 id="3-挑戰題病態輸入防護">3. 挑戰題：病態輸入防護</h3>
<p>設計一個安全的正則表達式驗證器，拒絕可能導致 ReDoS 的模式：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// Challenge: ReDoS-safe regex validator
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="sd">/// Validate that a regex pattern is safe from ReDoS attacks
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="sd">/// Unsafe patterns to detect:
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="sd">/// 1. Nested quantifiers: (a+)+
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="sd">/// 2. Overlapping alternatives: (a|a)+
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="sd">/// 3. Long quantified groups with wildcards: (.*)+
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">is_safe_pattern</span><span class="p">(</span><span class="n">pattern</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="c1">// Strategy 1: Try to compile with Rust regex
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// Rust regex rejects inherently unsafe patterns
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">match</span><span class="w"> </span><span class="n">regex</span>::<span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="n">pattern</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="kc">true</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">            </span><span class="c1">// Check if error is due to unsupported features
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="c1">// vs actual syntax errors
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">error_msg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">to_string</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="n">error_msg</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="s">&#34;backreference&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">                </span><span class="o">||</span><span class="w"> </span><span class="n">error_msg</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="s">&#34;look&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">                </span><span class="c1">// Potentially unsafe pattern
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"></span><span class="w">                </span><span class="nb">Ok</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">                </span><span class="c1">// Syntax error
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"></span><span class="w">                </span><span class="nb">Err</span><span class="p">(</span><span class="n">pyo3</span>::<span class="n">exceptions</span>::<span class="n">PyValueError</span>::<span class="n">new_err</span><span class="p">(</span><span class="n">error_msg</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w"></span><span class="sd">/// Benchmark a pattern to detect slow execution
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">benchmark_pattern</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">    </span><span class="n">pattern</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">    </span><span class="n">test_input</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">    </span><span class="n">max_ms</span>: <span class="kt">u64</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">    </span><span class="c1">// TODO: Implement timeout-based safety check
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// 1. Compile the pattern
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// 2. Run match with timeout
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">// 3. Return false if exceeds max_ms
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://docs.rs/regex/">Rust regex crate 文件</a> - 完整的 API 文件與效能說明</li>
<li><a href="https://swtch.com/~rsc/regexp/">正則表達式引擎比較</a> - Russ Cox 的經典系列文章</li>
<li><a href="https://pyo3.rs/">PyO3 User Guide</a> - PyO3 完整教學</li>
<li><a href="https://docs.rs/once_cell/">once_cell crate</a> - 延遲初始化最佳實踐</li>
<li><a href="https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS">ReDoS 攻擊與防護</a> - OWASP 安全指南</li>
</ul>
<hr>
<p><em>上一章：<a href="/blog/python-advanced/06-rust-extensions/case-studies/pyo3-parser/" data-link-title="案例：PyO3 文字解析" data-link-desc="用 PyO3 和 Rust 實現高效能的 Markdown 連結解析器">PyO3 文字解析</a></em>
<em>返回：<a href="/blog/python-advanced/06-rust-extensions/" data-link-title="模組六：用 Rust 擴展 Python" data-link-desc="學習使用 PyO3 和 Maturin 用 Rust 擴展 Python">模組六：用 Rust 擴展 Python</a></em></p>
]]></content:encoded></item><item><title>5.2 PyO3 基礎</title><link>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/pyo3-basics/</link><pubDate>Tue, 20 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/pyo3-basics/</guid><description>&lt;p>本章介紹 PyO3，Rust 的 Python 綁定函式庫。&lt;/p>
&lt;h2 id="本章目標">本章目標&lt;/h2>
&lt;p>學完本章後，你將能夠：&lt;/p>
&lt;ol>
&lt;li>理解 PyO3 的設計原理&lt;/li>
&lt;li>使用 #[pyfunction] 和 #[pyclass] 建立綁定&lt;/li>
&lt;li>處理型別轉換和錯誤&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="原理層pyo3-的設計">【原理層】PyO3 的設計&lt;/h2>
&lt;h3 id="pyo3-是什麼">PyO3 是什麼？&lt;/h3>
&lt;p>PyO3 是 Rust 與 Python 之間的橋樑：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">PyO3 提供：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">├── Rust → Python：將 Rust 程式碼編譯為 Python 模組
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">├── Python → Rust：在 Rust 中嵌入 Python 直譯器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">├── 型別轉換：自動處理 Rust ↔ Python 型別
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">└── GIL 管理：安全地處理 Python 的全域直譯器鎖&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="版本要求">版本要求&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c"># Cargo.toml（2025 年建議）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">pyo3&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.23&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;extension-module&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="c"># 支援的版本：&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="c"># - Rust: 1.63+（建議 1.75+）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c"># - Python: 3.8+&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">&lt;span class="c"># - PyO3: 0.23+（支援 Free-threading）&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="與-python-的互動模型">與 Python 的互動模型&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">Python 程式
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl"> │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> ↓ import
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">┌─────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">│ Rust 編譯的 .so/.pyd 模組 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">│ ┌─────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">│ │ PyO3 綁定層 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">│ │ - 型別轉換 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">│ │ - GIL 管理 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">│ │ - 錯誤處理 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">│ └─────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">│ ┌─────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">│ │ 純 Rust 程式碼 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">│ │ - 核心邏輯 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">│ │ - 無 GIL 限制 │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">│ └─────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">└─────────────────────────────────┘&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="設計層專案設定">【設計層】專案設定&lt;/h2>
&lt;h3 id="cargotoml-設定">Cargo.toml 設定&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">package&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_rust_module&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">edition&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;2021&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">lib&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_rust_module&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">crate-type&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;cdylib&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c"># 編譯為動態連結庫&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">pyo3&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.23&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;extension-module&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c"># 選用功能&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c"># pyo3 = { version = &amp;#34;0.23&amp;#34;, features = [&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="c"># &amp;#34;extension-module&amp;#34;,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="c"># &amp;#34;abi3-py38&amp;#34;, # 穩定 ABI（支援 Python 3.8+）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="c"># &amp;#34;multiple-pymethods&amp;#34;,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c"># ]}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="基本模組結構">基本模組結構&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">// src/lib.rs
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="sd">/// 簡單的加法函式
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>: &lt;span class="kt">i64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>: &lt;span class="kt">i64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="kt">i64&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="sd">/// 建立 Python 模組
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="cp">#[pymodule]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">my_rust_module&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyModule&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="abi3穩定-abi">abi3：穩定 ABI&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c"># 啟用 abi3 的好處：&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c"># 1. 一次編譯，多版本 Python 使用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="c"># 2. 減少發布的 wheel 數量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c"># 3. 更好的向前相容性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="nx">pyo3&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.23&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;extension-module&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;abi3-py38&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">不使用 abi3：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">├── my_module-cp38-cp38-linux_x86_64.whl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">├── my_module-cp39-cp39-linux_x86_64.whl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">├── my_module-cp310-cp310-linux_x86_64.whl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">├── my_module-cp311-cp311-linux_x86_64.whl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">└── my_module-cp312-cp312-linux_x86_64.whl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">使用 abi3-py38：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">└── my_module-cp38-abi3-linux_x86_64.whl # 支援 Python 3.8+&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="實作層函式綁定">【實作層】函式綁定&lt;/h2>
&lt;h3 id="pyfunction-基礎">#[pyfunction] 基礎&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 基本函式
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">greet&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="kt">str&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">String&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello, &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">!&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 帶預設參數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pyo3(signature = (a, b=1.0))]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">divide&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>: &lt;span class="kt">f64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>: &lt;span class="kt">f64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="kt">f64&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 可變參數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pyo3(signature = (*args))]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">sum_all&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">args&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">i64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="kt">i64&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">iter&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">sum&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 關鍵字參數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pyo3(signature = (**kwargs))]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">print_kwargs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">kwargs&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&amp;amp;&lt;/span>&lt;span class="n">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyDict&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dict&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dict&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">iter&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 文件字串
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="sd">/// 計算兩個數的最大公因數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl">&lt;span class="sd">///
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl">&lt;span class="sd">/// Args:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">&lt;span class="sd">/// a: 第一個整數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl">&lt;span class="sd">/// b: 第二個整數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl">&lt;span class="sd">///
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl">&lt;span class="sd">/// Returns:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">43&lt;/span>&lt;span class="cl">&lt;span class="sd">/// 最大公因數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">44&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">45&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>: &lt;span class="kt">u64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>: &lt;span class="kt">u64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="kt">u64&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">46&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">47&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">48&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">49&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymodule]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">50&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">my_module&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyModule&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">51&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">greet&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">52&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">divide&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">53&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sum_all&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">54&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">print_kwargs&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">55&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">gcd&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">56&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">57&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="型別轉換">型別轉換&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">types&lt;/span>::&lt;span class="p">{&lt;/span>&lt;span class="n">PyList&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyDict&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyTuple&lt;/span>&lt;span class="p">};&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 自動型別轉換
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">process_list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">items&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">i64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">i64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// Python list 自動轉換為 Vec
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">iter&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">collect&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">process_dict&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>: &lt;span class="nc">HashMap&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">i64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="kt">i64&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// Python dict 自動轉換為 HashMap
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">values&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">sum&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 手動處理 Python 物件
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">manual_conversion&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">obj&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyAny&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 檢查型別
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">obj&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">is_instance_of&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">PyList&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">list&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">obj&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">downcast&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">PyList&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;List with &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s"> items&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">obj&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">is_instance_of&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">PyDict&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dict&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">obj&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">downcast&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">PyDict&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Dict with &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s"> keys&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dict&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Unknown type: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">obj&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get_type&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 回傳多個值（使用 tuple）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">divmod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>: &lt;span class="kt">i64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>: &lt;span class="kt">i64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="p">(&lt;/span>&lt;span class="kt">i64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">i64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 回傳 Option（轉換為 None 或值）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">find_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">items&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">i64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">target&lt;/span>: &lt;span class="kt">i64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">usize&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">iter&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">position&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&amp;amp;&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">target&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="實作層類別綁定">【實作層】類別綁定&lt;/h2>
&lt;h3 id="pyclass-基礎">#[pyclass] 基礎&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pyclass]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">Point&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[pyo3(get, set)]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 自動產生 getter 和 setter
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>: &lt;span class="kt">f64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[pyo3(get, set)]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>: &lt;span class="kt">f64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymethods]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 建構子
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">#[new]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>: &lt;span class="kt">f64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>: &lt;span class="kt">f64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">Self&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 方法
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">distance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">other&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Point&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="kt">f64&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dx&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">other&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dy&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">other&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dx&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dx&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dy&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dy&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 類別方法
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">#[classmethod]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">origin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_cls&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyType&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">Self&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>: &lt;span class="mf">0.0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>: &lt;span class="mf">0.0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 靜態方法
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">#[staticmethod]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">from_polar&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">r&lt;/span>: &lt;span class="kt">f64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">theta&lt;/span>: &lt;span class="kt">f64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">Self&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>: &lt;span class="nc">r&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">theta&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">cos&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>: &lt;span class="nc">r&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">theta&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">sin&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// __repr__
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">__repr__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">String&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">43&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Point(&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">, &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">44&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">45&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">46&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// __str__
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">47&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">__str__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">String&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">48&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;(&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">, &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">49&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">50&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">51&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">52&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymodule]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">53&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">geometry&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyModule&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">54&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_class&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">55&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">56&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Python 使用：&lt;/p></description><content:encoded><![CDATA[<p>本章介紹 PyO3，Rust 的 Python 綁定函式庫。</p>
<h2 id="本章目標">本章目標</h2>
<p>學完本章後，你將能夠：</p>
<ol>
<li>理解 PyO3 的設計原理</li>
<li>使用 #[pyfunction] 和 #[pyclass] 建立綁定</li>
<li>處理型別轉換和錯誤</li>
</ol>
<hr>
<h2 id="原理層pyo3-的設計">【原理層】PyO3 的設計</h2>
<h3 id="pyo3-是什麼">PyO3 是什麼？</h3>
<p>PyO3 是 Rust 與 Python 之間的橋樑：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">PyO3 提供：
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── Rust → Python：將 Rust 程式碼編譯為 Python 模組
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── Python → Rust：在 Rust 中嵌入 Python 直譯器
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── 型別轉換：自動處理 Rust ↔ Python 型別
</span></span><span class="line"><span class="ln">5</span><span class="cl">└── GIL 管理：安全地處理 Python 的全域直譯器鎖</span></span></code></pre></div><h3 id="版本要求">版本要求</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="c"># Cargo.toml（2025 年建議）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.23&#34;</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c"># 支援的版本：</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c"># - Rust: 1.63+（建議 1.75+）</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c"># - Python: 3.8+</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="c"># - PyO3: 0.23+（支援 Free-threading）</span></span></span></code></pre></div><h3 id="與-python-的互動模型">與 Python 的互動模型</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Python 程式
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    │
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    ↓ import
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">┌─────────────────────────────────┐
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│  Rust 編譯的 .so/.pyd 模組      │
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">│  ┌─────────────────────────┐   │
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│  │  PyO3 綁定層            │   │
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">│  │  - 型別轉換             │   │
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">│  │  - GIL 管理             │   │
</span></span><span class="line"><span class="ln">10</span><span class="cl">│  │  - 錯誤處理             │   │
</span></span><span class="line"><span class="ln">11</span><span class="cl">│  └─────────────────────────┘   │
</span></span><span class="line"><span class="ln">12</span><span class="cl">│  ┌─────────────────────────┐   │
</span></span><span class="line"><span class="ln">13</span><span class="cl">│  │  純 Rust 程式碼         │   │
</span></span><span class="line"><span class="ln">14</span><span class="cl">│  │  - 核心邏輯             │   │
</span></span><span class="line"><span class="ln">15</span><span class="cl">│  │  - 無 GIL 限制          │   │
</span></span><span class="line"><span class="ln">16</span><span class="cl">│  └─────────────────────────┘   │
</span></span><span class="line"><span class="ln">17</span><span class="cl">└─────────────────────────────────┘</span></span></code></pre></div><hr>
<h2 id="設計層專案設定">【設計層】專案設定</h2>
<h3 id="cargotoml-設定">Cargo.toml 設定</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">package</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my_rust_module&#34;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">edition</span> <span class="p">=</span> <span class="s2">&#34;2021&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">lib</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my_rust_module&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">crate-type</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;cdylib&#34;</span><span class="p">]</span>  <span class="c"># 編譯為動態連結庫</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.23&#34;</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c"># 選用功能</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c"># pyo3 = { version = &#34;0.23&#34;, features = [</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c">#     &#34;extension-module&#34;,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c">#     &#34;abi3-py38&#34;,        # 穩定 ABI（支援 Python 3.8+）</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c">#     &#34;multiple-pymethods&#34;,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c"># ]}</span></span></span></code></pre></div><h3 id="基本模組結構">基本模組結構</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// src/lib.rs
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="sd">/// 簡單的加法函式
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span>: <span class="kt">i64</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="kt">i64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">i64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="n">a</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="sd">/// 建立 Python 模組
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="sd"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">my_rust_module</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">add</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="abi3穩定-abi">abi3：穩定 ABI</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="c"># 啟用 abi3 的好處：</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c"># 1. 一次編譯，多版本 Python 使用</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c"># 2. 減少發布的 wheel 數量</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c"># 3. 更好的向前相容性</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.23&#34;</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">,</span> <span class="s2">&#34;abi3-py38&#34;</span><span class="p">]</span> <span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">不使用 abi3：
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── my_module-cp38-cp38-linux_x86_64.whl
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── my_module-cp39-cp39-linux_x86_64.whl
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── my_module-cp310-cp310-linux_x86_64.whl
</span></span><span class="line"><span class="ln">5</span><span class="cl">├── my_module-cp311-cp311-linux_x86_64.whl
</span></span><span class="line"><span class="ln">6</span><span class="cl">└── my_module-cp312-cp312-linux_x86_64.whl
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl">使用 abi3-py38：
</span></span><span class="line"><span class="ln">9</span><span class="cl">└── my_module-cp38-abi3-linux_x86_64.whl  # 支援 Python 3.8+</span></span></code></pre></div><hr>
<h2 id="實作層函式綁定">【實作層】函式綁定</h2>
<h3 id="pyfunction-基礎">#[pyfunction] 基礎</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="c1">// 基本函式
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;Hello, </span><span class="si">{}</span><span class="s">!&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="c1">// 帶預設參數
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="cp">#[pyo3(signature = (a, b=1.0))]</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">divide</span><span class="p">(</span><span class="n">a</span>: <span class="kt">f64</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="kt">f64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="n">a</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">b</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w"></span><span class="c1">// 可變參數
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w"></span><span class="cp">#[pyo3(signature = (*args))]</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">sum_all</span><span class="p">(</span><span class="n">args</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">i64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="n">args</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">sum</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w"></span><span class="c1">// 關鍵字參數
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w"></span><span class="cp">#[pyo3(signature = (**kwargs))]</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">print_kwargs</span><span class="p">(</span><span class="n">kwargs</span>: <span class="nb">Option</span><span class="o">&lt;&amp;</span><span class="n">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyDict</span><span class="o">&gt;&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">dict</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">kwargs</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">dict</span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;</span><span class="si">{}</span><span class="s">: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w"></span><span class="c1">// 文件字串
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="c1"></span><span class="sd">/// 計算兩個數的最大公因數
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="sd">/// Args:
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="sd">///     a: 第一個整數
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="sd">///     b: 第二個整數
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="sd">///
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="sd">/// Returns:
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="sd">///     最大公因數
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">gcd</span><span class="p">(</span><span class="n">a</span>: <span class="kt">u64</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="kt">u64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">u64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">gcd</span><span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">my_module</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">greet</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">divide</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">sum_all</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">print_kwargs</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">gcd</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="型別轉換">型別轉換</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">types</span>::<span class="p">{</span><span class="n">PyList</span><span class="p">,</span><span class="w"> </span><span class="n">PyDict</span><span class="p">,</span><span class="w"> </span><span class="n">PyTuple</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="c1">// 自動型別轉換
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">process_list</span><span class="p">(</span><span class="n">items</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="c1">// Python list 自動轉換為 Vec
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">items</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">2</span><span class="p">).</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">process_dict</span><span class="p">(</span><span class="n">data</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="kt">i64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">i64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="c1">// Python dict 自動轉換為 HashMap
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">data</span><span class="p">.</span><span class="n">values</span><span class="p">().</span><span class="n">sum</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="c1">// 手動處理 Python 物件
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">manual_conversion</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">obj</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyAny</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="c1">// 檢查型別
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">obj</span><span class="p">.</span><span class="n">is_instance_of</span>::<span class="o">&lt;</span><span class="n">PyList</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">obj</span><span class="p">.</span><span class="n">downcast</span>::<span class="o">&lt;</span><span class="n">PyList</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;List with </span><span class="si">{}</span><span class="s"> items&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">list</span><span class="p">.</span><span class="n">len</span><span class="p">()))</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">obj</span><span class="p">.</span><span class="n">is_instance_of</span>::<span class="o">&lt;</span><span class="n">PyDict</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">dict</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">obj</span><span class="p">.</span><span class="n">downcast</span>::<span class="o">&lt;</span><span class="n">PyDict</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;Dict with </span><span class="si">{}</span><span class="s"> keys&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">dict</span><span class="p">.</span><span class="n">len</span><span class="p">()))</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;Unknown type: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">obj</span><span class="p">.</span><span class="n">get_type</span><span class="p">().</span><span class="n">name</span><span class="p">()</span><span class="o">?</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w"></span><span class="c1">// 回傳多個值（使用 tuple）
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">divmod</span><span class="p">(</span><span class="n">a</span>: <span class="kt">i64</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="kt">i64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="p">(</span><span class="kt">i64</span><span class="p">,</span><span class="w"> </span><span class="kt">i64</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">    </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w"></span><span class="c1">// 回傳 Option（轉換為 None 或值）
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">find_item</span><span class="p">(</span><span class="n">items</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i64</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">target</span>: <span class="kt">i64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">    </span><span class="n">items</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">position</span><span class="p">(</span><span class="o">|&amp;</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">target</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><hr>
<h2 id="實作層類別綁定">【實作層】類別綁定</h2>
<h3 id="pyclass-基礎">#[pyclass] 基礎</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Point</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get, set)]</span><span class="w">  </span><span class="c1">// 自動產生 getter 和 setter
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">x</span>: <span class="kt">f64</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get, set)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="n">y</span>: <span class="kt">f64</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Point</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="c1">// 建構子
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">x</span>: <span class="kt">f64</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="kt">f64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">        </span><span class="n">Point</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">    </span><span class="c1">// 方法
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">distance</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">other</span>: <span class="kp">&amp;</span><span class="nc">Point</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">dx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">x</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">dy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">y</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="p">(</span><span class="n">dx</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">dx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">dy</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">dy</span><span class="p">).</span><span class="n">sqrt</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="c1">// 類別方法
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="cp">#[classmethod]</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">origin</span><span class="p">(</span><span class="n">_cls</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyType</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">        </span><span class="n">Point</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span>: <span class="mf">0.0</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="mf">0.0</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">    </span><span class="c1">// 靜態方法
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="cp">#[staticmethod]</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">from_polar</span><span class="p">(</span><span class="n">r</span>: <span class="kt">f64</span><span class="p">,</span><span class="w"> </span><span class="n">theta</span>: <span class="kt">f64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">        </span><span class="n">Point</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">            </span><span class="n">x</span>: <span class="nc">r</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">theta</span><span class="p">.</span><span class="n">cos</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">            </span><span class="n">y</span>: <span class="nc">r</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">theta</span><span class="p">.</span><span class="n">sin</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">    </span><span class="c1">// __repr__
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;Point(</span><span class="si">{}</span><span class="s">, </span><span class="si">{}</span><span class="s">)&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">    </span><span class="c1">// __str__
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__str__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;(</span><span class="si">{}</span><span class="s">, </span><span class="si">{}</span><span class="s">)&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">geometry</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">Point</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><p>Python 使用：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">geometry</span> <span class="kn">import</span> <span class="n">Point</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">p1</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">p2</span> <span class="o">=</span> <span class="n">Point</span><span class="o">.</span><span class="n">origin</span><span class="p">()</span>  <span class="c1"># 類別方法</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">p3</span> <span class="o">=</span> <span class="n">Point</span><span class="o">.</span><span class="n">from_polar</span><span class="p">(</span><span class="mf">5.0</span><span class="p">,</span> <span class="mf">0.927</span><span class="p">)</span>  <span class="c1"># 靜態方法</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">p1</span><span class="p">)</span>  <span class="c1"># (3.0, 4.0)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">p1</span><span class="p">))</span>  <span class="c1"># Point(3.0, 4.0)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">p1</span><span class="o">.</span><span class="n">distance</span><span class="p">(</span><span class="n">p2</span><span class="p">))</span>  <span class="c1"># 5.0</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">p1</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="mf">10.0</span>  <span class="c1"># setter</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">p1</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>  <span class="c1"># getter</span></span></span></code></pre></div><h3 id="運算子重載">運算子重載</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">ops</span>::<span class="p">{</span><span class="n">Add</span><span class="p">,</span><span class="w"> </span><span class="n">Sub</span><span class="p">,</span><span class="w"> </span><span class="n">Mul</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="n">x</span>: <span class="kt">f64</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="n">y</span>: <span class="kt">f64</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">x</span>: <span class="kt">f64</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="kt">f64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="n">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">    </span><span class="c1">// __add__
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__add__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">other</span>: <span class="kp">&amp;</span><span class="nc">Vector2D</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">        </span><span class="n">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">            </span><span class="n">x</span>: <span class="nc">self</span><span class="p">.</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">            </span><span class="n">y</span>: <span class="nc">self</span><span class="p">.</span><span class="n">y</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">y</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="c1">// __sub__
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__sub__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">other</span>: <span class="kp">&amp;</span><span class="nc">Vector2D</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="n">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">            </span><span class="n">x</span>: <span class="nc">self</span><span class="p">.</span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">            </span><span class="n">y</span>: <span class="nc">self</span><span class="p">.</span><span class="n">y</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">y</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">    </span><span class="c1">// __mul__（標量乘法）
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__mul__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">scalar</span>: <span class="kt">f64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">        </span><span class="n">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">            </span><span class="n">x</span>: <span class="nc">self</span><span class="p">.</span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">scalar</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">            </span><span class="n">y</span>: <span class="nc">self</span><span class="p">.</span><span class="n">y</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">scalar</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">    </span><span class="c1">// __rmul__（右乘）
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__rmul__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">scalar</span>: <span class="kt">f64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">__mul__</span><span class="p">(</span><span class="n">scalar</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">    </span><span class="c1">// __neg__
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__neg__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">        </span><span class="n">Vector2D</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">            </span><span class="n">x</span>: <span class="o">-</span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">            </span><span class="n">y</span>: <span class="o">-</span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w">    </span><span class="c1">// __eq__
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__eq__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">other</span>: <span class="kp">&amp;</span><span class="nc">Vector2D</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="w">        </span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">x</span><span class="p">).</span><span class="n">abs</span><span class="p">()</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mf">1e-10</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w">
</span></span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="w">        </span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">other</span><span class="p">.</span><span class="n">y</span><span class="p">).</span><span class="n">abs</span><span class="p">()</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mf">1e-10</span><span class="w">
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="w">    </span><span class="c1">// __len__（向量維度）
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__len__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="w">        </span><span class="mi">2</span><span class="w">
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">65</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="w">    </span><span class="c1">// __getitem__
</span></span></span><span class="line"><span class="ln">67</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">__getitem__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">index</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="w">        </span><span class="k">match</span><span class="w"> </span><span class="n">index</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">69</span><span class="cl"><span class="w">            </span><span class="mi">0</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="w">            </span><span class="mi">1</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">71</span><span class="cl"><span class="w">            </span><span class="n">_</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">PyIndexError</span>::<span class="n">new_err</span><span class="p">(</span><span class="s">&#34;Index out of range&#34;</span><span class="p">)),</span><span class="w">
</span></span></span><span class="line"><span class="ln">72</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">73</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">74</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">75</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">76</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;Vector2D(</span><span class="si">{}</span><span class="s">, </span><span class="si">{}</span><span class="s">)&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">y</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">77</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">78</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="繼承與多型">繼承與多型</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="c1">// 基礎類別
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span><span class="cp">#[pyclass(subclass)]</span><span class="w">  </span><span class="c1">// 允許被繼承
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"></span><span class="k">struct</span> <span class="nc">Animal</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="n">name</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Animal</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">name</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span><span class="n">Animal</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="c1">// 可被覆寫的方法
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">speak</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">        </span><span class="s">&#34;...&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w"></span><span class="c1">// 子類別
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span><span class="cp">#[pyclass(extends=Animal)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Dog</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Dog</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">name</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="p">(</span><span class="bp">Self</span><span class="p">,</span><span class="w"> </span><span class="n">Animal</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">        </span><span class="p">(</span><span class="n">Dog</span><span class="w"> </span><span class="p">{},</span><span class="w"> </span><span class="n">Animal</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">speak</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">        </span><span class="s">&#34;Woof!&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w"></span><span class="cp">#[pyclass(extends=Animal)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Cat</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Cat</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">name</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="p">(</span><span class="bp">Self</span><span class="p">,</span><span class="w"> </span><span class="n">Animal</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">        </span><span class="p">(</span><span class="n">Cat</span><span class="w"> </span><span class="p">{},</span><span class="w"> </span><span class="n">Animal</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">speak</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">        </span><span class="s">&#34;Meow!&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><hr>
<h2 id="實作層錯誤處理">【實作層】錯誤處理</h2>
<h3 id="pyresult-與錯誤轉換">PyResult 與錯誤轉換</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">exceptions</span>::<span class="p">{</span><span class="n">PyValueError</span><span class="p">,</span><span class="w"> </span><span class="n">PyTypeError</span><span class="p">,</span><span class="w"> </span><span class="n">PyIOError</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="c1">// 回傳 PyResult
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">safe_divide</span><span class="p">(</span><span class="n">a</span>: <span class="kt">f64</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="kt">f64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">PyValueError</span>::<span class="n">new_err</span><span class="p">(</span><span class="s">&#34;除數不能為零&#34;</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span><span class="c1">// 自訂錯誤類型
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">read_file_internal</span><span class="p">(</span><span class="n">path</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">io</span>::<span class="n">Error</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">    </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">read_to_string</span><span class="p">(</span><span class="n">path</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">read_file</span><span class="p">(</span><span class="n">path</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">    </span><span class="n">read_file_internal</span><span class="p">(</span><span class="n">path</span><span class="p">).</span><span class="n">map_err</span><span class="p">(</span><span class="o">|</span><span class="n">e</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">        </span><span class="n">PyIOError</span>::<span class="n">new_err</span><span class="p">(</span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;無法讀取檔案: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">    </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w"></span><span class="c1">// 使用 ? 運算子
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parse_and_double</span><span class="p">(</span><span class="n">s</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="kt">i64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">num</span>: <span class="kt">i64</span> <span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">parse</span><span class="p">().</span><span class="n">map_err</span><span class="p">(</span><span class="o">|</span><span class="n">_</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">        </span><span class="n">PyValueError</span>::<span class="n">new_err</span><span class="p">(</span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;無法解析為整數: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">    </span><span class="p">})</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w"></span><span class="c1">// 自動轉換 Rust 錯誤
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">thiserror</span>::<span class="n">Error</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Error, Debug)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w"></span><span class="k">enum</span> <span class="nc">MyError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">    </span><span class="cp">#[error(</span><span class="s">&#34;數值錯誤: {0}&#34;</span><span class="cp">)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">    </span><span class="n">ValueError</span><span class="p">(</span><span class="nb">String</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">    </span><span class="cp">#[error(</span><span class="s">&#34;IO 錯誤: {0}&#34;</span><span class="cp">)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">    </span><span class="n">IoError</span><span class="p">(</span><span class="cp">#[from]</span><span class="w"> </span><span class="n">io</span>::<span class="n">Error</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="nb">From</span><span class="o">&lt;</span><span class="n">MyError</span><span class="o">&gt;</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">PyErr</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">from</span><span class="p">(</span><span class="n">err</span>: <span class="nc">MyError</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyErr</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">        </span><span class="k">match</span><span class="w"> </span><span class="n">err</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">            </span><span class="n">MyError</span>::<span class="n">ValueError</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">PyValueError</span>::<span class="n">new_err</span><span class="p">(</span><span class="n">msg</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">            </span><span class="n">MyError</span>::<span class="n">IoError</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">PyIOError</span>::<span class="n">new_err</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">to_string</span><span class="p">()),</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">risky_operation</span><span class="p">(</span><span class="n">value</span>: <span class="kt">i64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="kt">i64</span><span class="p">,</span><span class="w"> </span><span class="n">MyError</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">MyError</span>::<span class="n">ValueError</span><span class="p">(</span><span class="s">&#34;負數不允許&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">()))</span><span class="w">
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">value</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="自訂異常">自訂異常</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">create_exception</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="c1">// 建立自訂異常
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"></span><span class="fm">create_exception!</span><span class="p">(</span><span class="n">my_module</span><span class="p">,</span><span class="w"> </span><span class="n">ValidationError</span><span class="p">,</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">exceptions</span>::<span class="n">PyException</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="fm">create_exception!</span><span class="p">(</span><span class="n">my_module</span><span class="p">,</span><span class="w"> </span><span class="n">ProcessingError</span><span class="p">,</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">exceptions</span>::<span class="n">PyException</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">validate_data</span><span class="p">(</span><span class="n">data</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">is_empty</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">ValidationError</span>::<span class="n">new_err</span><span class="p">(</span><span class="s">&#34;資料不能為空&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">ValidationError</span>::<span class="n">new_err</span><span class="p">(</span><span class="s">&#34;資料太長&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">my_module</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">&#34;ValidationError&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">.</span><span class="n">py</span><span class="p">().</span><span class="n">get_type</span>::<span class="o">&lt;</span><span class="n">ValidationError</span><span class="o">&gt;</span><span class="p">())</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">&#34;ProcessingError&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">.</span><span class="n">py</span><span class="p">().</span><span class="n">get_type</span>::<span class="o">&lt;</span><span class="n">ProcessingError</span><span class="o">&gt;</span><span class="p">())</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">validate_data</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><hr>
<h2 id="實作層gil-管理">【實作層】GIL 管理</h2>
<h3 id="釋放-gil">釋放 GIL</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="c1">// CPU 密集計算，應該釋放 GIL
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">heavy_computation</span><span class="p">(</span><span class="n">n</span>: <span class="kt">u64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="c1">// 釋放 GIL，允許其他 Python 執行緒執行
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">Python</span>::<span class="n">with_gil</span><span class="p">(</span><span class="o">|</span><span class="n">py</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">        </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">            </span><span class="c1">// 這裡的程式碼不持有 GIL
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">            </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="n">n</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">                </span><span class="n">result</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">f64</span><span class="p">).</span><span class="n">sin</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">f64</span><span class="p">).</span><span class="n">cos</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">            </span><span class="n">result</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="c1">// 或者使用 Python 參數
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parallel_sum</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">data</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">    </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="c1">// 可以安全地使用多執行緒
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">use</span><span class="w"> </span><span class="n">rayon</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">        </span><span class="n">data</span><span class="p">.</span><span class="n">par_iter</span><span class="p">().</span><span class="n">sum</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="需要-gil-的操作">需要 GIL 的操作</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">callback_example</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">callback</span>: <span class="nc">PyObject</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="c1">// 模擬一些計算
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">results</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i64</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">        </span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">10</span><span class="p">).</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">).</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="c1">// 呼叫 Python 回呼需要 GIL
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">results</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">        </span><span class="n">callback</span><span class="p">.</span><span class="n">call1</span><span class="p">(</span><span class="n">py</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">result</span><span class="p">,))</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">mixed_workload</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">n</span>: <span class="kt">u64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">results</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="n">n</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="c1">// 計算（釋放 GIL）
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">            </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">f64</span><span class="p">).</span><span class="n">sin</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="c1">// Python 互動（需要 GIL）
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="n">results</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">value</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">        </span><span class="c1">// 定期檢查是否有 Python 訊號（如 Ctrl+C）
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">1000</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">            </span><span class="n">py</span><span class="p">.</span><span class="n">check_signals</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">results</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><hr>
<h2 id="進階與-numpy-整合">【進階】與 NumPy 整合</h2>
<h3 id="numpy-crate">numpy crate</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.23&#34;</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">numpy</span> <span class="p">=</span> <span class="s2">&#34;0.23&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nx">ndarray</span> <span class="p">=</span> <span class="s2">&#34;0.16&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">numpy</span>::<span class="p">{</span><span class="n">PyArray1</span><span class="p">,</span><span class="w"> </span><span class="n">PyArray2</span><span class="p">,</span><span class="w"> </span><span class="n">PyReadonlyArray1</span><span class="p">,</span><span class="w"> </span><span class="n">PyReadonlyArray2</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">ndarray</span>::<span class="p">{</span><span class="n">Array1</span><span class="p">,</span><span class="w"> </span><span class="n">Array2</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="c1">// 接受 NumPy 陣列
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">array_sum</span><span class="p">(</span><span class="n">arr</span>: <span class="nc">PyReadonlyArray1</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="n">arr</span><span class="p">.</span><span class="n">as_array</span><span class="p">().</span><span class="n">sum</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="c1">// 回傳 NumPy 陣列
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">create_range</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">n</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyArray1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">arr</span>: <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Array1</span>::<span class="n">from_iter</span><span class="p">((</span><span class="mi">0</span><span class="o">..</span><span class="n">n</span><span class="p">).</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">f64</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="n">PyArray1</span>::<span class="n">from_owned_array</span><span class="p">(</span><span class="n">py</span><span class="p">,</span><span class="w"> </span><span class="n">arr</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w"></span><span class="c1">// 處理 2D 陣列
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">matrix_multiply</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">    </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">    </span><span class="n">a</span>: <span class="nc">PyReadonlyArray2</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="p">,</span><span class="w"> </span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">    </span><span class="n">b</span>: <span class="nc">PyReadonlyArray2</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="p">,</span><span class="w"> </span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="n">Bound</span><span class="o">&lt;</span><span class="na">&#39;py</span><span class="p">,</span><span class="w"> </span><span class="n">PyArray2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">as_array</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">.</span><span class="n">as_array</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">    </span><span class="c1">// 檢查維度
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">ncols</span><span class="p">()</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">b</span><span class="p">.</span><span class="n">nrows</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">PyValueError</span>::<span class="n">new_err</span><span class="p">(</span><span class="s">&#34;矩陣維度不匹配&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">    </span><span class="c1">// 計算（釋放 GIL）
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">        </span><span class="n">a</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="o">&amp;</span><span class="n">b</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">PyArray2</span>::<span class="n">from_owned_array</span><span class="p">(</span><span class="n">py</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w"></span><span class="c1">// 原地修改
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="c1"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">normalize_inplace</span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">arr</span>: <span class="nc">PyReadwriteArray1</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">arr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">as_array_mut</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">sum</span>: <span class="kt">f64</span> <span class="o">=</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">sum</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">sum</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">        </span><span class="n">arr</span><span class="p">.</span><span class="n">mapv_inplace</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">sum</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><hr>
<h2 id="思考題">思考題</h2>
<ol>
<li>PyO3 如何處理 Rust 的所有權系統和 Python 的垃圾回收之間的衝突？</li>
<li>什麼時候應該使用 <code>py.allow_threads()</code>？有什麼風險？</li>
<li>為什麼 PyO3 使用 <code>Bound&lt;'_, T&gt;</code> 而不是直接傳遞 Python 物件？</li>
</ol>
<h2 id="實作練習">實作練習</h2>
<ol>
<li>使用 PyO3 實現一個簡單的 Counter 類別，支援 <code>+</code>、<code>-</code>、<code>+=</code> 運算子</li>
<li>實現一個接受 Python 回呼的函式，用於處理大量資料</li>
<li>使用 numpy crate 實現一個高效能的向量運算函式</li>
</ol>
<h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://pyo3.rs/">PyO3 User Guide</a></li>
<li><a href="https://docs.rs/pyo3/">PyO3 API Documentation</a></li>
<li><a href="https://docs.rs/numpy/">numpy crate</a></li>
<li><a href="https://github.com/PyO3/pyo3/tree/main/examples">PyO3 Examples</a></li>
</ul>
<hr>
<p><em>上一章：<a href="/blog/python-advanced/06-rust-extensions/why-rust/" data-link-title="5.1 為什麼選擇 Rust？" data-link-desc="比較 Rust 與 C/C&#43;&#43; 作為 Python 擴展語言">為什麼選擇 Rust？</a></em>
<em>下一章：<a href="/blog/python-advanced/06-rust-extensions/maturin-workflow/" data-link-title="5.3 Maturin 開發流程" data-link-desc="使用 Maturin 建構和發布 Rust Python 套件">Maturin 開發流程</a></em></p>
]]></content:encoded></item><item><title>5.3 Maturin 開發流程</title><link>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/maturin-workflow/</link><pubDate>Tue, 20 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/maturin-workflow/</guid><description>&lt;p>本章介紹 Maturin，Rust Python 套件的建構工具。&lt;/p>
&lt;h2 id="本章目標">本章目標&lt;/h2>
&lt;p>學完本章後，你將能夠：&lt;/p>
&lt;ol>
&lt;li>設定 Maturin 專案&lt;/li>
&lt;li>使用 maturin develop 快速迭代&lt;/li>
&lt;li>建構跨平台 wheel 並發布到 PyPI&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="原理層maturin-是什麼">【原理層】Maturin 是什麼？&lt;/h2>
&lt;h3 id="建構工具的角色">建構工具的角色&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">傳統 Python 擴展建構：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── setuptools + setup.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── 複雜的編譯器設定
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">├── 手動處理連結問題
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">└── 跨平台建構困難
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">Maturin 提供：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">├── 一鍵建構 Rust Python 套件
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">├── 自動處理 PyO3 設定
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">├── 跨平台 wheel 生成
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">├── 與 pyproject.toml 整合
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">└── 開發模式快速迭代&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="支援的專案類型">支援的專案類型&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">Maturin 支援：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">├── pyo3：純 Rust 擴展（最常用）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">├── cffi：生成 cffi 綁定
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">├── uniffi：跨語言綁定
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">└── bin：Rust 二進位程式打包&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="設計層專案設定">【設計層】專案設定&lt;/h2>
&lt;h3 id="安裝-maturin">安裝 Maturin&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 pip&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">pip install maturin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 pipx（推薦，隔離環境）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">pipx install maturin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 cargo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">cargo install maturin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 驗證安裝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">maturin --version&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="建立新專案">建立新專案&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 互動式建立&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">maturin new my_rust_module
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nb">cd&lt;/span> my_rust_module
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1"># 或者指定綁定類型&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">maturin new my_rust_module --bindings pyo3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1"># 專案結構&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">my_rust_module/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">├── Cargo.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">├── pyproject.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">│ └── lib.rs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">└── python/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> └── my_rust_module/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> └── __init__.py &lt;span class="c1"># 選用&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="pyprojecttoml-設定">pyproject.toml 設定&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;maturin&amp;gt;=1.5,&amp;lt;2.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;maturin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my-rust-module&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">description&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;A Python module written in Rust&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">requires-python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt;=3.8&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">classifiers&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Rust&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: Implementation :: CPython&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: Implementation :: PyPy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">optional-dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="nx">dev&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pytest&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;hypothesis&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">maturin&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="c"># 模組名稱（如果與 crate 名稱不同）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="nx">module-name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_rust_module&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="c"># Python 原始碼目錄（如果有純 Python 程式碼）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="nx">python-source&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;python&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="c"># 功能標誌&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pyo3/extension-module&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="c"># 啟用 abi3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="c"># features = [&amp;#34;pyo3/extension-module&amp;#34;, &amp;#34;pyo3/abi3-py38&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="c"># 排除不需要的檔案&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="nx">exclude&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tests/*&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;benches/*&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="c"># 建構設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="c"># strip = true # 移除除錯符號（減小檔案大小）&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="cargotoml-設定">Cargo.toml 設定&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">package&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_rust_module&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">edition&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;2021&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">lib&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_rust_module&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">crate-type&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;cdylib&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">pyo3&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.23&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;extension-module&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">profile&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">release&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="nx">lto&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span> &lt;span class="c"># Link-Time Optimization&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="nx">codegen-units&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c"># 更好的優化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">strip&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span> &lt;span class="c"># 移除除錯符號&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">profile&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dev&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="nx">opt-level&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="c"># 快速編譯&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="實作層開發流程">【實作層】開發流程&lt;/h2>
&lt;h3 id="maturin-develop">maturin develop&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 開發模式：編譯並安裝到當前虛擬環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">maturin develop
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 release 模式（較慢但更快的執行時效能）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">maturin develop --release
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 指定功能&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">maturin develop --features &lt;span class="s2">&amp;#34;some-feature&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 在其他虛擬環境中安裝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">maturin develop --target-dir target -E /path/to/venv
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用後立即測試&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">maturin develop &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> python -c &lt;span class="s2">&amp;#34;import my_rust_module; print(my_rust_module.add(1, 2))&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="完整開發循環">完整開發循環&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 1. 建立虛擬環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">python -m venv .venv
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nb">source&lt;/span> .venv/bin/activate &lt;span class="c1"># Linux/macOS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># .venv\Scripts\activate # Windows&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1"># 2. 安裝開發依賴&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">pip install maturin pytest
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># 3. 開發循環&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="k">while&lt;/span> editing:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 編輯 Rust 程式碼&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> vim src/lib.rs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 建構並安裝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> maturin develop
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 執行測試&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> pytest tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="c1"># 4. 準備發布&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">maturin build --release&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="混合-pythonrust-專案">混合 Python/Rust 專案&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">專案結構：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">my_package/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── Cargo.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">├── pyproject.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">│ └── lib.rs # Rust 程式碼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">└── python/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> └── my_package/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> ├── __init__.py # 匯入 Rust 模組
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> ├── utils.py # 純 Python 程式碼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> └── py.typed # 型別標記&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># python/my_package/__init__.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">.my_package&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="c1"># 從 Rust 模組匯入&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">.utils&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">helper_function&lt;/span> &lt;span class="c1"># 純 Python&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="n">__version__&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;0.1.0&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c"># pyproject.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">maturin&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">python-source&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;python&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="nx">module-name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_package.my_package&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="實作層建構與發布">【實作層】建構與發布&lt;/h2>
&lt;h3 id="maturin-build">maturin build&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建構 wheel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">maturin build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># Release 模式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">maturin build --release
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 指定 Python 版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">maturin build --interpreter python3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 多個 Python 版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">maturin build --interpreter python3.10 python3.11 python3.12
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 abi3（穩定 ABI）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">maturin build --release --features pyo3/abi3-py38
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建構結果位置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">ls target/wheels/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1"># my_rust_module-0.1.0-cp311-cp311-linux_x86_64.whl&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="跨平台建構">跨平台建構&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 Docker 建構 manylinux wheel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">maturin build --release --manylinux &lt;span class="m">2014&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 常用的 manylinux 版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1"># manylinux1: CentOS 5 (非常老舊)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1"># manylinux2010: CentOS 6&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># manylinux2014: CentOS 7 (推薦)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1"># manylinux_2_28: Debian 9 / Ubuntu 18.04&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 zig 進行交叉編譯&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">pip install ziglang
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">maturin build --release --target x86_64-unknown-linux-gnu --zig
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c1"># 常見目標平台&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="c1"># x86_64-unknown-linux-gnu&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="c1"># aarch64-unknown-linux-gnu&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="c1"># x86_64-apple-darwin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1"># aarch64-apple-darwin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="c1"># x86_64-pc-windows-msvc&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="發布到-pypi">發布到 PyPI&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 發布到 TestPyPI（測試）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">maturin publish --repository testpypi
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 發布到 PyPI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">maturin publish
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 API token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">maturin publish --username __token__ --password &amp;lt;your-pypi-token&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 或者設定環境變數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">MATURIN_PYPI_TOKEN&lt;/span>&lt;span class="o">=&lt;/span>&amp;lt;your-pypi-token&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">maturin publish&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="實作層cicd-整合">【實作層】CI/CD 整合&lt;/h2>
&lt;h3 id="github-actions">GitHub Actions&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># .github/workflows/build.yml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build and Publish&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tags&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s1">&amp;#39;v*&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pull_request&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 10&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 11&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 12&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Linux&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 14&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">linux&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 15&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 16&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">strategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 17&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matrix&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 18&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">x86_64, aarch64]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 19&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 20&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 21&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 22&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/setup-python@v5&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 23&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 24&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">python-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.11&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 25&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 26&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build wheels&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 27&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PyO3/maturin-action@v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 28&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 29&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ matrix.target }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 30&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">args&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>--&lt;span class="l">release --out dist&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 31&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">manylinux&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">auto&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 32&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 33&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Upload wheels&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 34&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/upload-artifact@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 35&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 36&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">wheels-linux-${{ matrix.target }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 37&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dist&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 38&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 39&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># macOS&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 40&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">macos&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 41&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">macos-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 42&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">strategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 43&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matrix&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 44&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">x86_64, aarch64]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 45&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 46&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 47&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 48&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/setup-python@v5&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 49&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 50&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">python-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.11&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 51&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 52&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build wheels&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 53&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PyO3/maturin-action@v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 54&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 55&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ matrix.target }}-apple-darwin&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 56&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">args&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>--&lt;span class="l">release --out dist&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 57&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 58&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Upload wheels&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 59&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/upload-artifact@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 60&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 61&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">wheels-macos-${{ matrix.target }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 62&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dist&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 63&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 64&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Windows&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 65&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">windows&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 66&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">windows-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 67&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 68&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 69&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 70&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/setup-python@v5&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 71&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 72&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">python-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.11&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 73&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 74&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build wheels&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 75&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PyO3/maturin-action@v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 76&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 77&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">args&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>--&lt;span class="l">release --out dist&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 78&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 79&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Upload wheels&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 80&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/upload-artifact@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 81&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 82&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">wheels-windows&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 83&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dist&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 84&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 85&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># 發布&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 86&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">publish&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 87&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">needs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">linux, macos, windows]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 88&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 89&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">if&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">startsWith(github.ref, &amp;#39;refs/tags/&amp;#39;)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 90&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 91&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/download-artifact@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 92&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 93&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pattern&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">wheels-*&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 94&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">merge-multiple&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 95&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dist&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 96&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 97&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Publish to PyPI&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 98&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PyO3/maturin-action@v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 99&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">100&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MATURIN_PYPI_TOKEN&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.PYPI_API_TOKEN }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">101&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">102&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">upload&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">103&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">args&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>--&lt;span class="l">non-interactive --skip-existing dist/*&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="測試工作流程">測試工作流程&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># .github/workflows/test.yml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">main]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pull_request&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ matrix.os }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">strategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matrix&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">os&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">ubuntu-latest, macos-latest, windows-latest]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">python-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;3.9&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.10&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.11&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.12&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/setup-python@v5&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">python-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ matrix.python-version }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install Rust&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dtolnay/rust-toolchain@stable&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install maturin&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pip install maturin pytest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build and install&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">maturin develop&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Run tests&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytest tests/&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="進階效能優化">【進階】效能優化&lt;/h2>
&lt;h3 id="編譯優化">編譯優化&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c"># Cargo.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">profile&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">release&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">lto&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;fat&amp;#34;&lt;/span> &lt;span class="c"># 最佳化連結（較慢編譯）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="nx">codegen-units&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c"># 單一編譯單元（更好優化）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="nx">panic&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;abort&amp;#34;&lt;/span> &lt;span class="c"># 不展開 panic（較小二進位）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="nx">strip&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span> &lt;span class="c"># 移除符號&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">&lt;span class="c"># 針對特定 CPU 優化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">&lt;span class="c"># RUSTFLAGS=&amp;#34;-C target-cpu=native&amp;#34; maturin build --release&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="減小二進位大小">減小二進位大小&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># Cargo.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">profile&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">release&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">opt-level&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;z&amp;#34;&lt;/span> &lt;span class="c"># 優化大小而非速度&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">lto&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="nx">strip&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">panic&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;abort&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c"># 使用 features 減少不需要的程式碼&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">pyo3&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.23&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">default-features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;extension-module&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="除錯技巧">除錯技巧&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 保留除錯符號&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">maturin develop --profile dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 啟用 Rust backtrace&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="nv">RUST_BACKTRACE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> python -c &lt;span class="s2">&amp;#34;import my_module; my_module.buggy_function()&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 lldb/gdb&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">lldb python
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">&lt;span class="o">(&lt;/span>lldb&lt;span class="o">)&lt;/span> run -c &lt;span class="s2">&amp;#34;import my_module; my_module.buggy_function()&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="常見問題疑難排解">【常見問題】疑難排解&lt;/h2>
&lt;h3 id="編譯錯誤">編譯錯誤&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">問題：找不到 Python
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">解決：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">1. 確認 Python 在 PATH 中
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">2. 使用 --interpreter 指定路徑
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> maturin develop --interpreter /usr/bin/python3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">問題：連結錯誤（Linux）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">解決：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">1. 安裝 python3-dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> sudo apt install python3-dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">2. 安裝 build-essential
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> sudo apt install build-essential
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">問題：找不到 PyO3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">解決：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">1. 確認 Cargo.toml 中有正確的 pyo3 依賴
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">2. 執行 cargo update&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="執行時錯誤">執行時錯誤&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">問題：ImportError: undefined symbol
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">原因：模組和 Python 版本不匹配
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">解決：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">1. 重新建構
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> maturin develop
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">2. 確認使用正確的 Python
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> which python
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">問題：記憶體錯誤 / Segfault
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">原因：通常是 unsafe 程式碼或 GIL 問題
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">解決：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">1. 檢查 unsafe 區塊
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">2. 確認正確使用 py.allow_threads()
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">3. 使用 RUST_BACKTRACE=1 獲取堆疊追蹤&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="完整範例專案">完整範例專案&lt;/h2>
&lt;h3 id="專案結構">專案結構&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">fibonacci_rs/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── Cargo.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── pyproject.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">│ └── lib.rs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">├── python/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">│ └── fibonacci_rs/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">│ ├── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">│ └── py.typed
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">├── tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">│ └── test_fib.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">└── README.md&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="完整程式碼">完整程式碼&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># Cargo.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">package&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;fibonacci_rs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="nx">edition&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;2021&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">lib&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;fibonacci_rs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">crate-type&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;cdylib&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">pyo3&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.23&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;extension-module&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">profile&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">release&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="nx">lto&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">codegen-units&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># pyproject.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;maturin&amp;gt;=1.5,&amp;lt;2.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;maturin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;fibonacci-rs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">description&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Fast Fibonacci implementation in Rust&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">requires-python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt;=3.8&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">maturin&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="nx">python-source&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;python&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="nx">module-name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;fibonacci_rs._core&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">// src/lib.rs
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="sd">/// 計算 Fibonacci 數列第 n 項
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">fib&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>: &lt;span class="kt">u64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="kt">u64&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="k">u64&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="k">u64&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">_&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">..=&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">tmp&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">tmp&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="sd">/// 計算 Fibonacci 數列前 n 項
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">fib_sequence&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">n&lt;/span>: &lt;span class="kt">usize&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">u64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">allow_threads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">seq&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Vec&lt;/span>::&lt;span class="n">with_capacity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="k">u64&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="k">u64&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">_&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">..&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">seq&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">tmp&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">tmp&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">seq&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymodule]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">_core&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyModule&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fib&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fib_sequence&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># python/fibonacci_rs/__init__.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">._core&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">fib&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">fib_sequence&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="n">__all__&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;fib&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;fib_sequence&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="n">__version__&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;0.1.0&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># tests/test_fib.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">fibonacci_rs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_fib_zero&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">fibonacci_rs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fib&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_fib_one&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">fibonacci_rs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fib&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_fib_ten&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">fibonacci_rs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fib&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">55&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_fib_sequence&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> &lt;span class="n">seq&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fibonacci_rs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fib_sequence&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">seq&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">13&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">21&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">34&lt;/span>&lt;span class="p">]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="思考題">思考題&lt;/h2>
&lt;ol>
&lt;li>為什麼 Maturin 使用 &lt;code>cdylib&lt;/code> crate type？與 &lt;code>rlib&lt;/code> 有什麼差異？&lt;/li>
&lt;li>abi3 功能如何減少需要建構的 wheel 數量？有什麼限制？&lt;/li>
&lt;li>在 CI 中建構跨平台 wheel 時，最大的挑戰是什麼？&lt;/li>
&lt;/ol>
&lt;h2 id="實作練習">實作練習&lt;/h2>
&lt;ol>
&lt;li>建立一個新的 Maturin 專案，實現一個簡單的字串處理函式&lt;/li>
&lt;li>設定 GitHub Actions 自動建構並發布到 TestPyPI&lt;/li>
&lt;li>比較 &lt;code>maturin develop&lt;/code> 和 &lt;code>maturin develop --release&lt;/code> 的編譯時間和執行效能&lt;/li>
&lt;/ol>
&lt;h2 id="延伸閱讀">延伸閱讀&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.maturin.rs/">Maturin 官方文件&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/PyO3/maturin">Maturin GitHub&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/PyO3/maturin-action">PyO3/maturin-action&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://packaging.python.org/">Python Packaging User Guide&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;em>上一章：&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/pyo3-basics/" data-link-title="5.2 PyO3 基礎" data-link-desc="使用 PyO3 建立 Rust 與 Python 的綁定">PyO3 基礎&lt;/a>&lt;/em>
&lt;em>下一章：&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/real-world-examples/" data-link-title="5.4 實戰案例分析" data-link-desc="分析知名 Python 專案如何使用 Rust">實戰案例分析&lt;/a>&lt;/em>&lt;/p></description><content:encoded><![CDATA[<p>本章介紹 Maturin，Rust Python 套件的建構工具。</p>
<h2 id="本章目標">本章目標</h2>
<p>學完本章後，你將能夠：</p>
<ol>
<li>設定 Maturin 專案</li>
<li>使用 maturin develop 快速迭代</li>
<li>建構跨平台 wheel 並發布到 PyPI</li>
</ol>
<hr>
<h2 id="原理層maturin-是什麼">【原理層】Maturin 是什麼？</h2>
<h3 id="建構工具的角色">建構工具的角色</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">傳統 Python 擴展建構：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── setuptools + setup.py
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── 複雜的編譯器設定
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">├── 手動處理連結問題
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">└── 跨平台建構困難
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">Maturin 提供：
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── 一鍵建構 Rust Python 套件
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── 自動處理 PyO3 設定
</span></span><span class="line"><span class="ln">10</span><span class="cl">├── 跨平台 wheel 生成
</span></span><span class="line"><span class="ln">11</span><span class="cl">├── 與 pyproject.toml 整合
</span></span><span class="line"><span class="ln">12</span><span class="cl">└── 開發模式快速迭代</span></span></code></pre></div><h3 id="支援的專案類型">支援的專案類型</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Maturin 支援：
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── pyo3：純 Rust 擴展（最常用）
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── cffi：生成 cffi 綁定
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── uniffi：跨語言綁定
</span></span><span class="line"><span class="ln">5</span><span class="cl">└── bin：Rust 二進位程式打包</span></span></code></pre></div><hr>
<h2 id="設計層專案設定">【設計層】專案設定</h2>
<h3 id="安裝-maturin">安裝 Maturin</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 使用 pip</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">pip install maturin
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 使用 pipx（推薦，隔離環境）</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">pipx install maturin
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 使用 cargo</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">cargo install maturin
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 驗證安裝</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">maturin --version</span></span></code></pre></div><h3 id="建立新專案">建立新專案</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 互動式建立</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">maturin new my_rust_module
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nb">cd</span> my_rust_module
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 或者指定綁定類型</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">maturin new my_rust_module --bindings pyo3
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># 專案結構</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">my_rust_module/
</span></span><span class="line"><span class="ln">10</span><span class="cl">├── Cargo.toml
</span></span><span class="line"><span class="ln">11</span><span class="cl">├── pyproject.toml
</span></span><span class="line"><span class="ln">12</span><span class="cl">├── src/
</span></span><span class="line"><span class="ln">13</span><span class="cl">│   └── lib.rs
</span></span><span class="line"><span class="ln">14</span><span class="cl">└── python/
</span></span><span class="line"><span class="ln">15</span><span class="cl">    └── my_rust_module/
</span></span><span class="line"><span class="ln">16</span><span class="cl">        └── __init__.py  <span class="c1"># 選用</span></span></span></code></pre></div><h3 id="pyprojecttoml-設定">pyproject.toml 設定</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;maturin&gt;=1.5,&lt;2.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;maturin&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my-rust-module&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s2">&#34;A Python module written in Rust&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.8&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">classifiers</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="s2">&#34;Programming Language :: Rust&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: Implementation :: CPython&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: Implementation :: PyPy&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="nx">dev</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pytest&#34;</span><span class="p">,</span> <span class="s2">&#34;hypothesis&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">maturin</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c"># 模組名稱（如果與 crate 名稱不同）</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="nx">module-name</span> <span class="p">=</span> <span class="s2">&#34;my_rust_module&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c"># Python 原始碼目錄（如果有純 Python 程式碼）</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="nx">python-source</span> <span class="p">=</span> <span class="s2">&#34;python&#34;</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c"># 功能標誌</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pyo3/extension-module&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c"># 啟用 abi3</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="c"># features = [&#34;pyo3/extension-module&#34;, &#34;pyo3/abi3-py38&#34;]</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="c"># 排除不需要的檔案</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="nx">exclude</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;tests/*&#34;</span><span class="p">,</span> <span class="s2">&#34;benches/*&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="c"># 建構設定</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="c"># strip = true  # 移除除錯符號（減小檔案大小）</span></span></span></code></pre></div><h3 id="cargotoml-設定">Cargo.toml 設定</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">package</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my_rust_module&#34;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">edition</span> <span class="p">=</span> <span class="s2">&#34;2021&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">lib</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my_rust_module&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">crate-type</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;cdylib&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.23&#34;</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">[</span><span class="nx">profile</span><span class="p">.</span><span class="nx">release</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nx">lto</span> <span class="p">=</span> <span class="kc">true</span>          <span class="c"># Link-Time Optimization</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nx">codegen-units</span> <span class="p">=</span> <span class="mi">1</span>   <span class="c"># 更好的優化</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">strip</span> <span class="p">=</span> <span class="kc">true</span>        <span class="c"># 移除除錯符號</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">[</span><span class="nx">profile</span><span class="p">.</span><span class="nx">dev</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="nx">opt-level</span> <span class="p">=</span> <span class="mi">0</span>       <span class="c"># 快速編譯</span></span></span></code></pre></div><hr>
<h2 id="實作層開發流程">【實作層】開發流程</h2>
<h3 id="maturin-develop">maturin develop</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 開發模式：編譯並安裝到當前虛擬環境</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">maturin develop
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 使用 release 模式（較慢但更快的執行時效能）</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">maturin develop --release
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 指定功能</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">maturin develop --features <span class="s2">&#34;some-feature&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 在其他虛擬環境中安裝</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">maturin develop --target-dir target -E /path/to/venv
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"># 使用後立即測試</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">maturin develop <span class="o">&amp;&amp;</span> python -c <span class="s2">&#34;import my_rust_module; print(my_rust_module.add(1, 2))&#34;</span></span></span></code></pre></div><h3 id="完整開發循環">完整開發循環</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 1. 建立虛擬環境</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">python -m venv .venv
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nb">source</span> .venv/bin/activate  <span class="c1"># Linux/macOS</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># .venv\Scripts\activate   # Windows</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"># 2. 安裝開發依賴</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">pip install maturin pytest
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 3. 開發循環</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">while</span> editing:
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="c1"># 編輯 Rust 程式碼</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    vim src/lib.rs
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="c1"># 建構並安裝</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    maturin develop
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="c1"># 執行測試</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    pytest tests/
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c1"># 4. 準備發布</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">maturin build --release</span></span></code></pre></div><h3 id="混合-pythonrust-專案">混合 Python/Rust 專案</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">專案結構：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">my_package/
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── Cargo.toml
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">├── pyproject.toml
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">├── src/
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">│   └── lib.rs              # Rust 程式碼
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">└── python/
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    └── my_package/
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        ├── __init__.py     # 匯入 Rust 模組
</span></span><span class="line"><span class="ln">10</span><span class="cl">        ├── utils.py        # 純 Python 程式碼
</span></span><span class="line"><span class="ln">11</span><span class="cl">        └── py.typed        # 型別標記</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># python/my_package/__init__.py</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">from</span> <span class="nn">.my_package</span> <span class="kn">import</span> <span class="o">*</span>  <span class="c1"># 從 Rust 模組匯入</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">helper_function</span>  <span class="c1"># 純 Python</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&#34;0.1.0&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="c"># pyproject.toml</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">maturin</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">python-source</span> <span class="p">=</span> <span class="s2">&#34;python&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nx">module-name</span> <span class="p">=</span> <span class="s2">&#34;my_package.my_package&#34;</span></span></span></code></pre></div><hr>
<h2 id="實作層建構與發布">【實作層】建構與發布</h2>
<h3 id="maturin-build">maturin build</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 建構 wheel</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">maturin build
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># Release 模式</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">maturin build --release
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 指定 Python 版本</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">maturin build --interpreter python3.11
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 多個 Python 版本</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">maturin build --interpreter python3.10 python3.11 python3.12
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"># 使用 abi3（穩定 ABI）</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">maturin build --release --features pyo3/abi3-py38
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"># 建構結果位置</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">ls target/wheels/
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"># my_rust_module-0.1.0-cp311-cp311-linux_x86_64.whl</span></span></span></code></pre></div><h3 id="跨平台建構">跨平台建構</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 使用 Docker 建構 manylinux wheel</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">maturin build --release --manylinux <span class="m">2014</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 常用的 manylinux 版本</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># manylinux1:   CentOS 5 (非常老舊)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"># manylinux2010: CentOS 6</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># manylinux2014: CentOS 7 (推薦)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># manylinux_2_28: Debian 9 / Ubuntu 18.04</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 使用 zig 進行交叉編譯</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">pip install ziglang
</span></span><span class="line"><span class="ln">12</span><span class="cl">maturin build --release --target x86_64-unknown-linux-gnu --zig
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"># 常見目標平台</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"># x86_64-unknown-linux-gnu</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"># aarch64-unknown-linux-gnu</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c1"># x86_64-apple-darwin</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"># aarch64-apple-darwin</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"># x86_64-pc-windows-msvc</span></span></span></code></pre></div><h3 id="發布到-pypi">發布到 PyPI</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 發布到 TestPyPI（測試）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">maturin publish --repository testpypi
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 發布到 PyPI</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">maturin publish
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 使用 API token</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">maturin publish --username __token__ --password &lt;your-pypi-token&gt;
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 或者設定環境變數</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nb">export</span> <span class="nv">MATURIN_PYPI_TOKEN</span><span class="o">=</span>&lt;your-pypi-token&gt;
</span></span><span class="line"><span class="ln">12</span><span class="cl">maturin publish</span></span></code></pre></div><hr>
<h2 id="實作層cicd-整合">【實作層】CI/CD 整合</h2>
<h3 id="github-actions">GitHub Actions</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">  1</span><span class="cl"><span class="c"># .github/workflows/build.yml</span><span class="w">
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build and Publish</span><span class="w">
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="w">    </span><span class="nt">tags</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">  7</span><span class="cl"><span class="w">      </span>- <span class="s1">&#39;v*&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="w">      </span>- <span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 13</span><span class="cl"><span class="w">  </span><span class="c"># Linux</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 14</span><span class="cl"><span class="w">  </span><span class="nt">linux</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 15</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="w">    </span><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 17</span><span class="cl"><span class="w">      </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 18</span><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">x86_64, aarch64]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 19</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 21</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 22</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 23</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 24</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;3.11&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 26</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build wheels</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 27</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">PyO3/maturin-action@v1</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="w">          </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.target }}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="w">          </span><span class="nt">args</span><span class="p">:</span><span class="w"> </span>--<span class="l">release --out dist</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 31</span><span class="cl"><span class="w">          </span><span class="nt">manylinux</span><span class="p">:</span><span class="w"> </span><span class="l">auto</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 32</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 33</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Upload wheels</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/upload-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 35</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 36</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">wheels-linux-${{ matrix.target }}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 37</span><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dist</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 38</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 39</span><span class="cl"><span class="w">  </span><span class="c"># macOS</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="w">  </span><span class="nt">macos</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">macos-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 42</span><span class="cl"><span class="w">    </span><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 43</span><span class="cl"><span class="w">      </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 44</span><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">x86_64, aarch64]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 45</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 46</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 47</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 48</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 49</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 50</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;3.11&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 52</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build wheels</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">PyO3/maturin-action@v1</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 55</span><span class="cl"><span class="w">          </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.target }}-apple-darwin</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 56</span><span class="cl"><span class="w">          </span><span class="nt">args</span><span class="p">:</span><span class="w"> </span>--<span class="l">release --out dist</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 57</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 58</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Upload wheels</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 59</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/upload-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 60</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 61</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">wheels-macos-${{ matrix.target }}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 62</span><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dist</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 63</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 64</span><span class="cl"><span class="w">  </span><span class="c"># Windows</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 65</span><span class="cl"><span class="w">  </span><span class="nt">windows</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 66</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">windows-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 67</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 68</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 69</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 70</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 71</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;3.11&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 73</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 74</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build wheels</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 75</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">PyO3/maturin-action@v1</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 76</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 77</span><span class="cl"><span class="w">          </span><span class="nt">args</span><span class="p">:</span><span class="w"> </span>--<span class="l">release --out dist</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 78</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 79</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Upload wheels</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 80</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/upload-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 81</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 82</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">wheels-windows</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 83</span><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dist</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 84</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 85</span><span class="cl"><span class="w">  </span><span class="c"># 發布</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 86</span><span class="cl"><span class="w">  </span><span class="nt">publish</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 87</span><span class="cl"><span class="w">    </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">linux, macos, windows]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 88</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 89</span><span class="cl"><span class="w">    </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">startsWith(github.ref, &#39;refs/tags/&#39;)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 90</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 91</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/download-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 92</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 93</span><span class="cl"><span class="w">          </span><span class="nt">pattern</span><span class="p">:</span><span class="w"> </span><span class="l">wheels-*</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 94</span><span class="cl"><span class="w">          </span><span class="nt">merge-multiple</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 95</span><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dist</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 96</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 97</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Publish to PyPI</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 98</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">PyO3/maturin-action@v1</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 99</span><span class="cl"><span class="w">        </span><span class="nt">env</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">100</span><span class="cl"><span class="w">          </span><span class="nt">MATURIN_PYPI_TOKEN</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.PYPI_API_TOKEN }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">101</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">102</span><span class="cl"><span class="w">          </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="l">upload</span><span class="w">
</span></span></span><span class="line"><span class="ln">103</span><span class="cl"><span class="w">          </span><span class="nt">args</span><span class="p">:</span><span class="w"> </span>--<span class="l">non-interactive --skip-existing dist/*</span></span></span></code></pre></div><h3 id="測試工作流程">測試工作流程</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># .github/workflows/test.yml</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Test</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">  </span><span class="nt">test</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.os }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">      </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span><span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">ubuntu-latest, macos-latest, windows-latest]</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s1">&#39;3.9&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;3.10&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;3.11&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;3.12&#39;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.python-version }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Install Rust</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">dtolnay/rust-toolchain@stable</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Install maturin</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">pip install maturin pytest</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build and install</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">maturin develop</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Run tests</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">pytest tests/</span></span></span></code></pre></div><hr>
<h2 id="進階效能優化">【進階】效能優化</h2>
<h3 id="編譯優化">編譯優化</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="c"># Cargo.toml</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="p">[</span><span class="nx">profile</span><span class="p">.</span><span class="nx">release</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">lto</span> <span class="p">=</span> <span class="s2">&#34;fat&#34;</span>         <span class="c"># 最佳化連結（較慢編譯）</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nx">codegen-units</span> <span class="p">=</span> <span class="mi">1</span>   <span class="c"># 單一編譯單元（更好優化）</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nx">panic</span> <span class="p">=</span> <span class="s2">&#34;abort&#34;</span>     <span class="c"># 不展開 panic（較小二進位）</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nx">strip</span> <span class="p">=</span> <span class="kc">true</span>        <span class="c"># 移除符號</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="c"># 針對特定 CPU 優化</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="c"># RUSTFLAGS=&#34;-C target-cpu=native&#34; maturin build --release</span></span></span></code></pre></div><h3 id="減小二進位大小">減小二進位大小</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># Cargo.toml</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="p">[</span><span class="nx">profile</span><span class="p">.</span><span class="nx">release</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">opt-level</span> <span class="p">=</span> <span class="s2">&#34;z&#34;</span>     <span class="c"># 優化大小而非速度</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">lto</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="nx">strip</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">panic</span> <span class="p">=</span> <span class="s2">&#34;abort&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c"># 使用 features 減少不需要的程式碼</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.23&#34;</span><span class="p">,</span> <span class="nx">default-features</span> <span class="p">=</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">]</span> <span class="p">}</span></span></span></code></pre></div><h3 id="除錯技巧">除錯技巧</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 保留除錯符號</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">maturin develop --profile dev
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 啟用 Rust backtrace</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nv">RUST_BACKTRACE</span><span class="o">=</span><span class="m">1</span> python -c <span class="s2">&#34;import my_module; my_module.buggy_function()&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 使用 lldb/gdb</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">lldb python
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="o">(</span>lldb<span class="o">)</span> run -c <span class="s2">&#34;import my_module; my_module.buggy_function()&#34;</span></span></span></code></pre></div><hr>
<h2 id="常見問題疑難排解">【常見問題】疑難排解</h2>
<h3 id="編譯錯誤">編譯錯誤</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">問題：找不到 Python
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">解決：
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">1. 確認 Python 在 PATH 中
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">2. 使用 --interpreter 指定路徑
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">   maturin develop --interpreter /usr/bin/python3.11
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">問題：連結錯誤（Linux）
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">解決：
</span></span><span class="line"><span class="ln">11</span><span class="cl">1. 安裝 python3-dev
</span></span><span class="line"><span class="ln">12</span><span class="cl">   sudo apt install python3-dev
</span></span><span class="line"><span class="ln">13</span><span class="cl">2. 安裝 build-essential
</span></span><span class="line"><span class="ln">14</span><span class="cl">   sudo apt install build-essential
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">問題：找不到 PyO3
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">解決：
</span></span><span class="line"><span class="ln">19</span><span class="cl">1. 確認 Cargo.toml 中有正確的 pyo3 依賴
</span></span><span class="line"><span class="ln">20</span><span class="cl">2. 執行 cargo update</span></span></code></pre></div><h3 id="執行時錯誤">執行時錯誤</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">問題：ImportError: undefined symbol
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">原因：模組和 Python 版本不匹配
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">解決：
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">1. 重新建構
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">   maturin develop
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">2. 確認使用正確的 Python
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   which python
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">問題：記憶體錯誤 / Segfault
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">原因：通常是 unsafe 程式碼或 GIL 問題
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">解決：
</span></span><span class="line"><span class="ln">16</span><span class="cl">1. 檢查 unsafe 區塊
</span></span><span class="line"><span class="ln">17</span><span class="cl">2. 確認正確使用 py.allow_threads()
</span></span><span class="line"><span class="ln">18</span><span class="cl">3. 使用 RUST_BACKTRACE=1 獲取堆疊追蹤</span></span></code></pre></div><hr>
<h2 id="完整範例專案">完整範例專案</h2>
<h3 id="專案結構">專案結構</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">fibonacci_rs/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── Cargo.toml
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── pyproject.toml
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">├── src/
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│   └── lib.rs
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── python/
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│   └── fibonacci_rs/
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">│       ├── __init__.py
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">│       └── py.typed
</span></span><span class="line"><span class="ln">10</span><span class="cl">├── tests/
</span></span><span class="line"><span class="ln">11</span><span class="cl">│   └── test_fib.py
</span></span><span class="line"><span class="ln">12</span><span class="cl">└── README.md</span></span></code></pre></div><h3 id="完整程式碼">完整程式碼</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># Cargo.toml</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="p">[</span><span class="nx">package</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;fibonacci_rs&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="nx">edition</span> <span class="p">=</span> <span class="s2">&#34;2021&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="p">[</span><span class="nx">lib</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;fibonacci_rs&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">crate-type</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;cdylib&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">[</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">pyo3</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.23&#34;</span><span class="p">,</span> <span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;extension-module&#34;</span><span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">[</span><span class="nx">profile</span><span class="p">.</span><span class="nx">release</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nx">lto</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">codegen-units</span> <span class="p">=</span> <span class="mi">1</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># pyproject.toml</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;maturin&gt;=1.5,&lt;2.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;maturin&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;fibonacci-rs&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s2">&#34;Fast Fibonacci implementation in Rust&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.8&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">maturin</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">python-source</span> <span class="p">=</span> <span class="s2">&#34;python&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nx">module-name</span> <span class="p">=</span> <span class="s2">&#34;fibonacci_rs._core&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// src/lib.rs
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="sd">/// 計算 Fibonacci 數列第 n 項
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span>: <span class="kt">u64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">u64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">n</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="k">u64</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="k">u64</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">2</span><span class="o">..=</span><span class="n">n</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">tmp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="n">b</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w"></span><span class="sd">/// 計算 Fibonacci 數列前 n 項
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">fib_sequence</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">n</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">u64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">    </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">seq</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">with_capacity</span><span class="p">(</span><span class="n">n</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="k">u64</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="k">u64</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="n">n</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">            </span><span class="n">seq</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">a</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">tmp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">            </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">            </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">        </span><span class="n">seq</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">    </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">_core</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">fib</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">fib_sequence</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># python/fibonacci_rs/__init__.py</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">from</span> <span class="nn">._core</span> <span class="kn">import</span> <span class="n">fib</span><span class="p">,</span> <span class="n">fib_sequence</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;fib&#34;</span><span class="p">,</span> <span class="s2">&#34;fib_sequence&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&#34;0.1.0&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># tests/test_fib.py</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">fibonacci_rs</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">def</span> <span class="nf">test_fib_zero</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="k">assert</span> <span class="n">fibonacci_rs</span><span class="o">.</span><span class="n">fib</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">def</span> <span class="nf">test_fib_one</span><span class="p">():</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="k">assert</span> <span class="n">fibonacci_rs</span><span class="o">.</span><span class="n">fib</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">def</span> <span class="nf">test_fib_ten</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">assert</span> <span class="n">fibonacci_rs</span><span class="o">.</span><span class="n">fib</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="o">==</span> <span class="mi">55</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="k">def</span> <span class="nf">test_fib_sequence</span><span class="p">():</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="n">seq</span> <span class="o">=</span> <span class="n">fibonacci_rs</span><span class="o">.</span><span class="n">fib_sequence</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="k">assert</span> <span class="n">seq</span> <span class="o">==</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">21</span><span class="p">,</span> <span class="mi">34</span><span class="p">]</span></span></span></code></pre></div><hr>
<h2 id="思考題">思考題</h2>
<ol>
<li>為什麼 Maturin 使用 <code>cdylib</code> crate type？與 <code>rlib</code> 有什麼差異？</li>
<li>abi3 功能如何減少需要建構的 wheel 數量？有什麼限制？</li>
<li>在 CI 中建構跨平台 wheel 時，最大的挑戰是什麼？</li>
</ol>
<h2 id="實作練習">實作練習</h2>
<ol>
<li>建立一個新的 Maturin 專案，實現一個簡單的字串處理函式</li>
<li>設定 GitHub Actions 自動建構並發布到 TestPyPI</li>
<li>比較 <code>maturin develop</code> 和 <code>maturin develop --release</code> 的編譯時間和執行效能</li>
</ol>
<h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://www.maturin.rs/">Maturin 官方文件</a></li>
<li><a href="https://github.com/PyO3/maturin">Maturin GitHub</a></li>
<li><a href="https://github.com/PyO3/maturin-action">PyO3/maturin-action</a></li>
<li><a href="https://packaging.python.org/">Python Packaging User Guide</a></li>
</ul>
<hr>
<p><em>上一章：<a href="/blog/python-advanced/06-rust-extensions/pyo3-basics/" data-link-title="5.2 PyO3 基礎" data-link-desc="使用 PyO3 建立 Rust 與 Python 的綁定">PyO3 基礎</a></em>
<em>下一章：<a href="/blog/python-advanced/06-rust-extensions/real-world-examples/" data-link-title="5.4 實戰案例分析" data-link-desc="分析知名 Python 專案如何使用 Rust">實戰案例分析</a></em></p>
]]></content:encoded></item><item><title>5.4 實戰案例分析</title><link>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/real-world-examples/</link><pubDate>Tue, 20 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/real-world-examples/</guid><description>&lt;p>本章分析幾個使用 Rust 的知名 Python 專案，學習實際應用的模式。&lt;/p>
&lt;h2 id="本章目標">本章目標&lt;/h2>
&lt;p>學完本章後，你將能夠：&lt;/p>
&lt;ol>
&lt;li>理解 Rust 在數值計算的應用&lt;/li>
&lt;li>理解 Rust 在文字處理的應用&lt;/li>
&lt;li>評估自己的專案是否適合使用 Rust&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="案例一數值計算實現快速排序">【案例一】數值計算：實現快速排序&lt;/h2>
&lt;h3 id="需求分析">需求分析&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">場景：需要對大量數值資料進行排序
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">問題：Python 內建排序雖然是 C 實現，但有特殊需求時需要自訂
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">實現目標：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">├── 支援自訂比較函式
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">├── 支援並行排序（大資料集）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">├── 與 NumPy 整合
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">└── 效能接近或超過 NumPy sort&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="rust-實現">Rust 實現&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">// src/lib.rs
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">numpy&lt;/span>::&lt;span class="p">{&lt;/span>&lt;span class="n">PyArray1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyReadonlyArray1&lt;/span>&lt;span class="p">};&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">rayon&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="sd">/// 並行快速排序
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">parallel_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>: &lt;span class="nc">PyReadonlyArray1&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyArray1&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">as_array&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 釋放 GIL 進行並行排序
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">allow_threads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_vec&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">par_sort_by&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">partial_cmp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">unwrap&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">PyArray1&lt;/span>::&lt;span class="n">from_vec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="sd">/// 部分排序（只排序前 k 個元素）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">partial_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>: &lt;span class="nc">PyReadonlyArray1&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">k&lt;/span>: &lt;span class="kt">usize&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyArray1&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">as_array&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Err&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PyValueError&lt;/span>::&lt;span class="n">new_err&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;k 大於陣列長度&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">allow_threads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_vec&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 使用 select_nth_unstable 獲得前 k 個最小元素
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">select_nth_unstable_by&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">partial_cmp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">unwrap&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="o">..&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="n">to_vec&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PyArray1&lt;/span>::&lt;span class="n">from_vec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="sd">/// 找出 top-k 元素（不完全排序，更快）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="cp">#[pyfunction]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">top_k&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>: &lt;span class="nc">PyReadonlyArray1&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">k&lt;/span>: &lt;span class="kt">usize&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyArray1&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">43&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">collections&lt;/span>::&lt;span class="n">BinaryHeap&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">44&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">cmp&lt;/span>::&lt;span class="n">Ordering&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">45&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">46&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 包裝 f64 以支援 BinaryHeap
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">47&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">#[derive(PartialEq)]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">48&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">MinFloat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">49&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">50&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Eq&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">MinFloat&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">51&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">52&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">PartialOrd&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">MinFloat&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">53&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">partial_cmp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">other&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Ordering&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">54&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 反向比較，使 BinaryHeap 成為 min-heap
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">55&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">other&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mf">0.&lt;/span>&lt;span class="n">partial_cmp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">56&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">57&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">58&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">59&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Ord&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">MinFloat&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">60&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">cmp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">other&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">Ordering&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">61&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">partial_cmp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">other&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">unwrap&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">62&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">63&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">64&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">65&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">as_array&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">66&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">67&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">allow_threads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">68&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">heap&lt;/span>: &lt;span class="nc">BinaryHeap&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MinFloat&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">BinaryHeap&lt;/span>::&lt;span class="n">with_capacity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">69&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">70&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">iter&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">71&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">heap&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">MinFloat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">72&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">heap&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">73&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">heap&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">pop&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">74&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">75&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">76&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">77&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">heap&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">into_sorted_vec&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">into_iter&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">collect&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">_&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">78&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">79&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">80&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PyArray1&lt;/span>::&lt;span class="n">from_vec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">81&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">82&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">83&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymodule]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">84&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">fast_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyModule&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">85&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">parallel_sort&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">86&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">partial_sort&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">87&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">wrap_pyfunction!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">top_k&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">88&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">89&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="效能比較">效能比較&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">fast_sort&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">timeit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1"># 測試資料&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1_000_000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rand&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># NumPy sort&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="n">t_numpy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">timeit&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">copy&lt;/span>&lt;span class="p">()),&lt;/span> &lt;span class="n">number&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># Rust parallel sort&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="n">t_rust&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">timeit&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">fast_sort&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parallel_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">number&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="c1"># 找 top-1000（Rust）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="n">t_topk_rust&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">timeit&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">fast_sort&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">top_k&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">number&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1"># 找 top-1000（NumPy: 完整排序後取前 k）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="n">t_topk_numpy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">timeit&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timeit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)[:&lt;/span>&lt;span class="mi">1000&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">number&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;完整排序 - NumPy: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">t_numpy&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.3f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">s, Rust: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">t_rust&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.3f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">s&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Top-1000 - NumPy: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">t_topk_numpy&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.3f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">s, Rust: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">t_topk_rust&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.3f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">s&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="c1"># 預期結果（依硬體而異）：&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="c1"># 完整排序 - NumPy: 0.85s, Rust: 0.45s（使用多核心）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="c1"># Top-1000 - NumPy: 0.85s, Rust: 0.02s（不需完整排序）&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="案例二文字處理高效能-tokenizer">【案例二】文字處理：高效能 Tokenizer&lt;/h2>
&lt;h3 id="需求分析-1">需求分析&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">場景：NLP 應用需要將文字切分為 tokens
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">問題：純 Python 實現太慢，無法處理大量文字
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">實現目標：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">├── 支援 Unicode
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">├── 支援正規表達式模式
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">├── 批次處理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">└── 與現有 NLP 工具整合&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="rust-實現-1">Rust 實現&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">// src/lib.rs
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">regex&lt;/span>::&lt;span class="n">Regex&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">rayon&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pyclass]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">Tokenizer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>: &lt;span class="nc">Regex&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">lowercase&lt;/span>: &lt;span class="kt">bool&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 10&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 11&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 12&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymethods]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 13&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Tokenizer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 14&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[new]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 15&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[pyo3(signature = (pattern=r&lt;/span>&lt;span class="s">&amp;#34;\w+&amp;#34;&lt;/span>&lt;span class="cp">, lowercase=true))]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 16&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pattern&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="kt">str&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">lowercase&lt;/span>: &lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="bp">Self&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 17&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Regex&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 18&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">map_err&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyValueError&lt;/span>::&lt;span class="n">new_err&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;無效的正規表達式: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)))&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 19&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tokenizer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">lowercase&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 20&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 21&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 22&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="sd">/// 對單一字串進行 tokenization
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 23&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">tokenize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="kt">str&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 24&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 25&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">find_iter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 26&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 27&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">as_str&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 28&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lowercase&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 29&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_lowercase&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 30&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 31&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 32&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 33&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 34&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">collect&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 35&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 36&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 37&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="sd">/// 批次 tokenization（並行處理）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 38&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">tokenize_batch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">texts&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 39&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">allow_threads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 40&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">texts&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 41&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">par_iter&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 42&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">tokenize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 43&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">collect&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 44&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 45&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 46&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 47&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="sd">/// 計算詞頻
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 48&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">count_tokens&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="kt">str&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">HashMap&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">usize&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 49&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">collections&lt;/span>::&lt;span class="n">HashMap&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 50&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 51&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">allow_threads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 52&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">counts&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">HashMap&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 53&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mat&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">find_iter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 54&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">token&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lowercase&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 55&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mat&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">as_str&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">to_lowercase&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 56&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 57&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mat&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">as_str&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 58&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">};&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 59&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">counts&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">entry&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">or_insert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 60&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 61&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">counts&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 62&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 63&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 64&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 65&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 66&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 簡單的 BPE（Byte Pair Encoding）實現
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 67&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyclass]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 68&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">SimpleBPE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 69&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">vocab&lt;/span>: &lt;span class="nc">HashMap&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">u32&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 70&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">merges&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 71&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 72&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 73&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymethods]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 74&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">SimpleBPE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 75&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[new]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 76&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">new&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">Self&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 77&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">SimpleBPE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 78&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">vocab&lt;/span>: &lt;span class="nc">HashMap&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 79&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">merges&lt;/span>: &lt;span class="nb">Vec&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 80&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 81&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 82&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 83&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="sd">/// 訓練 BPE
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 84&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">train&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">texts&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">vocab_size&lt;/span>: &lt;span class="kt">usize&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 85&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">collections&lt;/span>::&lt;span class="n">HashMap&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 86&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 87&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">allow_threads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 88&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 初始化：每個字元是一個 token
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 89&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word_freqs&lt;/span>: &lt;span class="nc">HashMap&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">usize&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">HashMap&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 90&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 91&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">texts&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 92&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">split_whitespace&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 93&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">chars&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">chars&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">()).&lt;/span>&lt;span class="n">collect&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 94&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">word_freqs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">entry&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chars&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">or_insert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 95&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 96&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 97&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 98&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 迭代合併最頻繁的 pair
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 99&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">while&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">vocab&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">vocab_size&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">100&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 計算 pair 頻率
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">101&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pair_freqs&lt;/span>: &lt;span class="nc">HashMap&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">usize&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">HashMap&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">102&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">103&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">freq&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">word_freqs&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">104&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">..&lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">saturating_sub&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">105&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pair&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">106&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">pair_freqs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">entry&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pair&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">or_insert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">freq&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">107&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">108&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">109&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">110&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 找出最頻繁的 pair
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">111&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">best_pair&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">_&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pair_freqs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">iter&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">max_by_key&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">freq&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">freq&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">112&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">new_token&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="si">{}{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">best_pair&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">best_pair&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">113&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">merges&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">best_pair&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">114&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">vocab&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">insert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_token&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">vocab&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">u32&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">115&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">116&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 更新 word_freqs
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">117&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">new_word_freqs&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">HashMap&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">118&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">freq&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word_freqs&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">119&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">new_word&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Vec&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">120&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">121&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">while&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">122&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&amp;amp;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">best_pair&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&amp;amp;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">best_pair&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">123&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">new_word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_token&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">124&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">125&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">126&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">new_word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">word&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">127&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">128&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">129&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">130&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">new_word_freqs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">entry&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_word&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">or_insert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">freq&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">131&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">132&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">word_freqs&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">new_word_freqs&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">133&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">134&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">135&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">136&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">137&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">138&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">139&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">140&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="sd">/// 編碼文字
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">141&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">encode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="kt">str&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">u32&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">142&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">tokens&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">chars&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">()).&lt;/span>&lt;span class="n">collect&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">143&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">144&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">merges&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">145&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">merged&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="si">{}{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">146&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">new_tokens&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Vec&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">147&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">148&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">while&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">tokens&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">149&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">tokens&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&amp;amp;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">tokens&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&amp;amp;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">tokens&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">150&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">new_tokens&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">merged&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">151&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">152&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">153&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">new_tokens&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tokens&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">154&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">155&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">156&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">157&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">tokens&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">new_tokens&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">158&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">159&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">160&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">tokens&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">161&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">iter&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">162&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">filter_map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">vocab&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">copied&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">163&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">collect&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">164&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">165&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">166&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">167&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">collections&lt;/span>::&lt;span class="n">HashMap&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">168&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">169&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymodule]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">170&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">fast_tokenizer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyModule&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">171&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_class&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Tokenizer&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">172&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_class&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">SimpleBPE&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">173&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">174&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="使用範例">使用範例&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fast_tokenizer&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Tokenizer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">SimpleBPE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="c1"># 基本 tokenization&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Tokenizer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;\w+&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">lowercase&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="n">text&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello, World! This is a test.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="n">tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tokenize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tokens&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># [&amp;#39;hello&amp;#39;, &amp;#39;world&amp;#39;, &amp;#39;this&amp;#39;, &amp;#39;is&amp;#39;, &amp;#39;a&amp;#39;, &amp;#39;test&amp;#39;]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 批次處理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="n">texts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;First sentence.&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Second sentence.&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Third one.&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="n">batch_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tokenize_batch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">texts&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch_tokens&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="c1"># 詞頻統計&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="n">counts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">count_tokens&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;the cat sat on the mat&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">counts&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># {&amp;#39;the&amp;#39;: 2, &amp;#39;cat&amp;#39;: 1, &amp;#39;sat&amp;#39;: 1, &amp;#39;on&amp;#39;: 1, &amp;#39;mat&amp;#39;: 1}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="c1"># BPE 訓練&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="n">bpe&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SimpleBPE&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="n">corpus&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;hello there&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;world peace&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="n">bpe&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">train&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">corpus&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">vocab_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="n">encoded&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">bpe&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">encoded&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="案例三資料驗證pydantic-風格驗證器">【案例三】資料驗證：Pydantic 風格驗證器&lt;/h2>
&lt;h3 id="需求分析-2">需求分析&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">場景：API 需要驗證大量輸入資料
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">問題：純 Python 驗證太慢（Pydantic v1 的問題）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">實現目標：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">├── 型別檢查
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">├── 範圍驗證
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">├── 自訂驗證函式
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">└── 清晰的錯誤訊息&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="rust-實現-2">Rust 實現&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">// src/lib.rs
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">prelude&lt;/span>::&lt;span class="o">*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">exceptions&lt;/span>::&lt;span class="n">PyValueError&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">collections&lt;/span>::&lt;span class="n">HashMap&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 驗證錯誤
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyclass]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[derive(Clone)]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 10&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[pyo3(get)]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 11&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 12&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[pyo3(get)]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 13&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 14&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 15&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 16&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymethods]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 17&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 18&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">__repr__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">String&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 19&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;ValidationError(field=&amp;#39;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#39;, message=&amp;#39;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#39;)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 20&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 21&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 22&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 23&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// 欄位驗證器
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 24&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyclass]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 25&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">Field&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 26&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>: &lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 27&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field_type&lt;/span>: &lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 28&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">required&lt;/span>: &lt;span class="kt">bool&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 29&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">min_value&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 30&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">max_value&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 31&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">min_length&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">usize&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 32&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">max_length&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">usize&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 33&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">regex&lt;/span>::&lt;span class="n">Regex&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 34&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 35&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 36&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymethods]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 37&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Field&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 38&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[new]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 39&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[pyo3(signature = (name, field_type, required=true, min_value=None, max_value=None, min_length=None, max_length=None, pattern=None))]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 40&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 41&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>: &lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 42&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field_type&lt;/span>: &lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 43&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">required&lt;/span>: &lt;span class="kt">bool&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 44&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">min_value&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 45&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">max_value&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 46&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">min_length&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">usize&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 47&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">max_length&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">usize&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 48&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>: &lt;span class="nb">Option&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 49&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="bp">Self&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 50&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">match&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 51&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">regex&lt;/span>::&lt;span class="n">Regex&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 52&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">map_err&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyValueError&lt;/span>::&lt;span class="n">new_err&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="fm">format!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;無效的正規表達式: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)))&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 53&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">None&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">None&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 54&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">};&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 55&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 56&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Field&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 57&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 58&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field_type&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 59&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">required&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 60&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">min_value&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 61&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">max_value&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 62&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">min_length&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 63&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">max_length&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 64&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 65&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 66&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 67&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 68&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 69&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">// Schema 驗證器
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 70&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#[pyclass]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 71&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">Schema&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 72&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">fields&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Field&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 73&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 74&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 75&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymethods]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 76&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Schema&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 77&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cp">#[new]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 78&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fields&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Py&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Field&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="bp">Self&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 79&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Python&lt;/span>::&lt;span class="n">with_gil&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 80&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">fields&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Field&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">fields&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 81&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">iter&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 82&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">borrow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 83&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">collect&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 84&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Schema&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">fields&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 85&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 86&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 87&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 88&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="sd">/// 驗證單一物件
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 89&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyDict&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 90&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Vec&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 91&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 92&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">fields&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 93&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 94&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 95&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">match&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 96&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">None&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 97&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">required&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 98&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 99&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">100&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="s">&amp;#34;此欄位為必填&amp;#34;&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">101&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">102&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">103&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">104&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">105&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 型別檢查
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">106&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">match&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">field_type&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">as_str&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">107&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;int&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">108&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">extract&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">i64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">109&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 範圍檢查
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">110&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">min&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">min_value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">111&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">min&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">112&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">113&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">114&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="nc">format&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;值必須 &amp;gt;= {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">min&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">115&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">116&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">117&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">118&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">max_value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">119&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">120&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">121&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">122&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="nc">format&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;值必須 &amp;lt;= {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">123&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">124&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">125&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">126&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">127&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">128&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">129&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="s">&amp;#34;必須是整數&amp;#34;&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">130&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">131&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">132&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">133&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;float&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">134&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">extract&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">f64&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">135&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">min&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">min_value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">136&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">min&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">137&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">138&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">139&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="nc">format&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;值必須 &amp;gt;= {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">min&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">140&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">141&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">142&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">143&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">max_value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">144&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">145&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">146&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">147&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="nc">format&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;值必須 &amp;lt;= {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">148&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">149&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">150&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">151&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">152&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">153&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">154&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="s">&amp;#34;必須是浮點數&amp;#34;&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">155&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">156&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">157&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">158&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">159&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">extract&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">160&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 長度檢查
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">161&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">min_len&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">min_length&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">162&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">min_len&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">163&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">164&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">165&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="nc">format&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;長度必須 &amp;gt;= {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">min_len&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">166&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">167&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">168&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">169&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max_len&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">max_length&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">170&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">len&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">max_len&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">171&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">172&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">173&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="nc">format&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;長度必須 &amp;lt;= {}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">max_len&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">174&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">175&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">176&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">177&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 正規表達式檢查
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">178&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Some&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">ref&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">179&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">pattern&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">is_match&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">180&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">181&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">182&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="s">&amp;#34;格式不符合要求&amp;#34;&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">183&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">184&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">185&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">186&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">187&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">188&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">field&lt;/span>: &lt;span class="nc">field&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">189&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>: &lt;span class="s">&amp;#34;必須是字串&amp;#34;&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">to_string&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">190&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">191&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">192&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">193&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">_&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">194&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">195&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">196&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">197&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">198&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">199&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">errors&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">200&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">201&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">202&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="sd">/// 批次驗證
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">203&lt;/span>&lt;span class="cl">&lt;span class="sd">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">validate_batch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">py&lt;/span>: &lt;span class="nc">Python&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data_list&lt;/span>: &lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyDict&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">Vec&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">204&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">results&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Vec&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">205&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data_list&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">206&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">results&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">py&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">207&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">208&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">results&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">209&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">210&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">211&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">212&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">pyo3&lt;/span>::&lt;span class="n">types&lt;/span>::&lt;span class="n">PyDict&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">213&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">214&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="cp">#[pymodule]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">215&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">fast_validator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">Bound&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">&amp;#39;_&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PyModule&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nc">PyResult&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">216&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_class&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Field&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">217&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_class&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Schema&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">218&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">add_class&lt;/span>::&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">ValidationError&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">219&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nb">Ok&lt;/span>&lt;span class="p">(())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">220&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="使用範例-1">使用範例&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fast_validator&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Field&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Schema&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="c1"># 定義 schema&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="n">schema&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Schema&lt;/span>&lt;span class="p">([&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="n">Field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">required&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">min_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">max_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> &lt;span class="n">Field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;int&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">required&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">min_value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">max_value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">150&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="n">Field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;str&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">required&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pattern&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;^[\w\.-]+@[\w\.-]+\.\w+$&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="n">Field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;score&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;float&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">required&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">min_value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">max_value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="c1"># 驗證資料&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Alice&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;alice@example.com&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="n">errors&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">schema&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">errors&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">e&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">errors&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;驗證通過&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">&lt;span class="c1"># 無效資料&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="n">invalid_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;invalid&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="n">errors&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">schema&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">invalid_data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">e&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">errors&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">field&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="c1"># name: 長度必須 &amp;gt;= 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="c1"># age: 值必須 &amp;gt;= 0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="c1"># email: 格式不符合要求&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="總結何時使用-rust">【總結】何時使用 Rust&lt;/h2>
&lt;h3 id="決策清單">決策清單&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">應該使用 Rust：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">1. 效能瓶頸明確
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl"> □ profiler 顯示特定函式占用大量時間
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> □ 純 Python 優化已到極限
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> □ 現有 C 擴展不滿足需求
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">2. 資料處理需求
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> □ 大量數值計算
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> □ 頻繁的字串處理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> □ 需要並行處理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">3. 安全性要求
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> □ 處理不可信的輸入
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> □ 需要避免記憶體錯誤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> □ 長期運行的服務
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">4. 跨平台需求
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> □ 需要支援多個作業系統
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> □ 需要支援多個 Python 版本
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">可能不需要 Rust：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">1. 效能不是主要瓶頸
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">2. 團隊沒有 Rust 經驗且時間緊迫
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">3. 專案規模小且不會長期維護
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">4. 可以用現有函式庫解決&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="最佳實踐">最佳實踐&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">1. 設計階段
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl"> ├── 明確定義 Python/Rust 邊界
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> ├── 最小化跨語言呼叫次數
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl"> ├── 使用批次處理減少開銷
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> └── 設計清晰的錯誤處理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">2. 開發階段
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> ├── 先用 Python 原型驗證邏輯
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> ├── 逐步將瓶頸移到 Rust
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> ├── 完善的測試覆蓋
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> └── 使用 maturin develop 快速迭代
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">3. 發布階段
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> ├── 使用 CI/CD 自動建構 wheel
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> ├── 支援主流 Python 版本
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> ├── 提供 fallback 純 Python 實現
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> └── 清楚的安裝文件&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="思考題">思考題&lt;/h2>
&lt;ol>
&lt;li>在設計 Rust 擴展的 API 時，如何平衡效能和易用性？&lt;/li>
&lt;li>如何處理 Rust 函式庫沒有 Python 綁定的情況？&lt;/li>
&lt;li>在什麼情況下，應該用 Cython 而不是 Rust？&lt;/li>
&lt;/ol>
&lt;h2 id="實作練習">實作練習&lt;/h2>
&lt;ol>
&lt;li>選擇一個你常用的純 Python 函式，用 Rust 重寫並比較效能&lt;/li>
&lt;li>分析 &lt;a href="https://github.com/pola-rs/polars">Polars&lt;/a> 的原始碼結構，理解大型 Rust Python 專案的組織方式&lt;/li>
&lt;li>實現一個簡單的 JSON parser，比較與 Python &lt;code>json&lt;/code> 模組的效能差異&lt;/li>
&lt;/ol>
&lt;h2 id="延伸閱讀">延伸閱讀&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/pola-rs/polars">Polars 原始碼&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/astral-sh/ruff">Ruff 原始碼&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/openai/tiktoken">tiktoken 原始碼&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/pydantic/pydantic-core">pydantic-core 原始碼&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;em>上一章：&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/maturin-workflow/" data-link-title="5.3 Maturin 開發流程" data-link-desc="使用 Maturin 建構和發布 Rust Python 套件">Maturin 開發流程&lt;/a>&lt;/em>
&lt;em>下一模組：&lt;a href="https://tarrragon.github.io/blog/python-advanced/07-packaging/" data-link-title="模組七：打包與發布" data-link-desc="學習現代 Python 套件的打包與發布流程">模組六：打包與發布&lt;/a>&lt;/em>&lt;/p></description><content:encoded><![CDATA[<p>本章分析幾個使用 Rust 的知名 Python 專案，學習實際應用的模式。</p>
<h2 id="本章目標">本章目標</h2>
<p>學完本章後，你將能夠：</p>
<ol>
<li>理解 Rust 在數值計算的應用</li>
<li>理解 Rust 在文字處理的應用</li>
<li>評估自己的專案是否適合使用 Rust</li>
</ol>
<hr>
<h2 id="案例一數值計算實現快速排序">【案例一】數值計算：實現快速排序</h2>
<h3 id="需求分析">需求分析</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">場景：需要對大量數值資料進行排序
</span></span><span class="line"><span class="ln">2</span><span class="cl">問題：Python 內建排序雖然是 C 實現，但有特殊需求時需要自訂
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">實現目標：
</span></span><span class="line"><span class="ln">5</span><span class="cl">├── 支援自訂比較函式
</span></span><span class="line"><span class="ln">6</span><span class="cl">├── 支援並行排序（大資料集）
</span></span><span class="line"><span class="ln">7</span><span class="cl">├── 與 NumPy 整合
</span></span><span class="line"><span class="ln">8</span><span class="cl">└── 效能接近或超過 NumPy sort</span></span></code></pre></div><h3 id="rust-實現">Rust 實現</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// src/lib.rs
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">numpy</span>::<span class="p">{</span><span class="n">PyArray1</span><span class="p">,</span><span class="w"> </span><span class="n">PyReadonlyArray1</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">rayon</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="sd">/// 並行快速排序
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">parallel_sort</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">arr</span>: <span class="nc">PyReadonlyArray1</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyArray1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">arr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">as_array</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="c1">// 釋放 GIL 進行並行排序
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">data</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">data</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">to_vec</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">        </span><span class="n">data</span><span class="p">.</span><span class="n">par_sort_by</span><span class="p">(</span><span class="o">|</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="o">|</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">partial_cmp</span><span class="p">(</span><span class="n">b</span><span class="p">).</span><span class="n">unwrap</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="n">data</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">    </span><span class="n">PyArray1</span>::<span class="n">from_vec</span><span class="p">(</span><span class="n">py</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w"></span><span class="sd">/// 部分排序（只排序前 k 個元素）
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">partial_sort</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">arr</span>: <span class="nc">PyReadonlyArray1</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">k</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="n">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyArray1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">arr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">as_array</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">PyValueError</span>::<span class="n">new_err</span><span class="p">(</span><span class="s">&#34;k 大於陣列長度&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">data</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">to_vec</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">        </span><span class="c1">// 使用 select_nth_unstable 獲得前 k 個最小元素
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="n">data</span><span class="p">.</span><span class="n">select_nth_unstable_by</span><span class="p">(</span><span class="n">k</span><span class="p">,</span><span class="w"> </span><span class="o">|</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="o">|</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">partial_cmp</span><span class="p">(</span><span class="n">b</span><span class="p">).</span><span class="n">unwrap</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">        </span><span class="n">data</span><span class="p">[</span><span class="o">..</span><span class="n">k</span><span class="p">].</span><span class="n">to_vec</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">PyArray1</span>::<span class="n">from_vec</span><span class="p">(</span><span class="n">py</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w"></span><span class="sd">/// 找出 top-k 元素（不完全排序，更快）
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="sd"></span><span class="cp">#[pyfunction]</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">top_k</span><span class="p">(</span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">arr</span>: <span class="nc">PyReadonlyArray1</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">k</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="n">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyArray1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">    </span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">BinaryHeap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">    </span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">cmp</span>::<span class="n">Ordering</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">    </span><span class="c1">// 包裝 f64 以支援 BinaryHeap
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="c1"></span><span class="w">    </span><span class="cp">#[derive(PartialEq)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">    </span><span class="k">struct</span> <span class="nc">MinFloat</span><span class="p">(</span><span class="kt">f64</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">    </span><span class="k">impl</span><span class="w"> </span><span class="nb">Eq</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">MinFloat</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="w">    </span><span class="k">impl</span><span class="w"> </span><span class="nb">PartialOrd</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">MinFloat</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">        </span><span class="k">fn</span> <span class="nf">partial_cmp</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">other</span>: <span class="kp">&amp;</span><span class="nc">Self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Ordering</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">            </span><span class="c1">// 反向比較，使 BinaryHeap 成為 min-heap
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="n">other</span><span class="p">.</span><span class="mf">0.</span><span class="n">partial_cmp</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="mi">0</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="w">    </span><span class="k">impl</span><span class="w"> </span><span class="nb">Ord</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">MinFloat</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="w">        </span><span class="k">fn</span> <span class="nf">cmp</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">other</span>: <span class="kp">&amp;</span><span class="nc">Self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Ordering</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">partial_cmp</span><span class="p">(</span><span class="n">other</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">65</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">arr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">as_array</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">67</span><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">heap</span>: <span class="nc">BinaryHeap</span><span class="o">&lt;</span><span class="n">MinFloat</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BinaryHeap</span>::<span class="n">with_capacity</span><span class="p">(</span><span class="n">k</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">69</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="o">&amp;</span><span class="n">x</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">arr</span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">71</span><span class="cl"><span class="w">            </span><span class="n">heap</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">MinFloat</span><span class="p">(</span><span class="n">x</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">72</span><span class="cl"><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="n">heap</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">73</span><span class="cl"><span class="w">                </span><span class="n">heap</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">74</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">75</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">76</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">77</span><span class="cl"><span class="w">        </span><span class="n">heap</span><span class="p">.</span><span class="n">into_sorted_vec</span><span class="p">().</span><span class="n">into_iter</span><span class="p">().</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="mi">0</span><span class="p">).</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;&gt;</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">78</span><span class="cl"><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">79</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">80</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">PyArray1</span>::<span class="n">from_vec</span><span class="p">(</span><span class="n">py</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">81</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">82</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">83</span><span class="cl"><span class="w"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">84</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">fast_sort</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">85</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">parallel_sort</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">86</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">partial_sort</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">87</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_function</span><span class="p">(</span><span class="fm">wrap_pyfunction!</span><span class="p">(</span><span class="n">top_k</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">88</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">89</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="效能比較">效能比較</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">fast_sort</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="nn">timeit</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 測試資料</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">n</span> <span class="o">=</span> <span class="mi">1_000_000</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># NumPy sort</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">t_numpy</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">timeit</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">copy</span><span class="p">()),</span> <span class="n">number</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># Rust parallel sort</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">t_rust</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">timeit</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="n">fast_sort</span><span class="o">.</span><span class="n">parallel_sort</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="n">number</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"># 找 top-1000（Rust）</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">t_topk_rust</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">timeit</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="n">fast_sort</span><span class="o">.</span><span class="n">top_k</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">1000</span><span class="p">),</span> <span class="n">number</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"># 找 top-1000（NumPy: 完整排序後取前 k）</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">t_topk_numpy</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">timeit</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">data</span><span class="p">)[:</span><span class="mi">1000</span><span class="p">],</span> <span class="n">number</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;完整排序 - NumPy: </span><span class="si">{</span><span class="n">t_numpy</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">s, Rust: </span><span class="si">{</span><span class="n">t_rust</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">s&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Top-1000 - NumPy: </span><span class="si">{</span><span class="n">t_topk_numpy</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">s, Rust: </span><span class="si">{</span><span class="n">t_topk_rust</span><span class="si">:</span><span class="s2">.3f</span><span class="si">}</span><span class="s2">s&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"># 預期結果（依硬體而異）：</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1"># 完整排序 - NumPy: 0.85s, Rust: 0.45s（使用多核心）</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"># Top-1000 - NumPy: 0.85s, Rust: 0.02s（不需完整排序）</span></span></span></code></pre></div><hr>
<h2 id="案例二文字處理高效能-tokenizer">【案例二】文字處理：高效能 Tokenizer</h2>
<h3 id="需求分析-1">需求分析</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">場景：NLP 應用需要將文字切分為 tokens
</span></span><span class="line"><span class="ln">2</span><span class="cl">問題：純 Python 實現太慢，無法處理大量文字
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">實現目標：
</span></span><span class="line"><span class="ln">5</span><span class="cl">├── 支援 Unicode
</span></span><span class="line"><span class="ln">6</span><span class="cl">├── 支援正規表達式模式
</span></span><span class="line"><span class="ln">7</span><span class="cl">├── 批次處理
</span></span><span class="line"><span class="ln">8</span><span class="cl">└── 與現有 NLP 工具整合</span></span></code></pre></div><h3 id="rust-實現-1">Rust 實現</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln">  1</span><span class="cl"><span class="c1">// src/lib.rs
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">regex</span>::<span class="n">Regex</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">rayon</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="w"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln">  7</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Tokenizer</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="w">    </span><span class="n">pattern</span>: <span class="nc">Regex</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="w">    </span><span class="n">lowercase</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 13</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Tokenizer</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 14</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 15</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(signature = (pattern=r</span><span class="s">&#34;\w+&#34;</span><span class="cp">, lowercase=true))]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">pattern</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">lowercase</span>: <span class="kt">bool</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 17</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">pattern</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="n">pattern</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 18</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map_err</span><span class="p">(</span><span class="o">|</span><span class="n">e</span><span class="o">|</span><span class="w"> </span><span class="n">PyValueError</span>::<span class="n">new_err</span><span class="p">(</span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;無效的正規表達式: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)))</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 19</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">Tokenizer</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">pattern</span><span class="p">,</span><span class="w"> </span><span class="n">lowercase</span><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 21</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 22</span><span class="cl"><span class="w">    </span><span class="sd">/// 對單一字串進行 tokenization
</span></span></span><span class="line"><span class="ln"> 23</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">tokenize</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">text</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 24</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">pattern</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 25</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">find_iter</span><span class="p">(</span><span class="n">text</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 26</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">m</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 27</span><span class="cl"><span class="w">                </span><span class="kd">let</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">m</span><span class="p">.</span><span class="n">as_str</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="w">                </span><span class="k">if</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">lowercase</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="w">                    </span><span class="n">s</span><span class="p">.</span><span class="n">to_lowercase</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 31</span><span class="cl"><span class="w">                    </span><span class="n">s</span><span class="p">.</span><span class="n">to_string</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 32</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 33</span><span class="cl"><span class="w">            </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 35</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 36</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 37</span><span class="cl"><span class="w">    </span><span class="sd">/// 批次 tokenization（並行處理）
</span></span></span><span class="line"><span class="ln"> 38</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">tokenize_batch</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">texts</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 39</span><span class="cl"><span class="w">        </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="w">            </span><span class="n">texts</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="w">                </span><span class="p">.</span><span class="n">par_iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 42</span><span class="cl"><span class="w">                </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">text</span><span class="o">|</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">tokenize</span><span class="p">(</span><span class="n">text</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 43</span><span class="cl"><span class="w">                </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 44</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 45</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 46</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 47</span><span class="cl"><span class="w">    </span><span class="sd">/// 計算詞頻
</span></span></span><span class="line"><span class="ln"> 48</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">count_tokens</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">text</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 49</span><span class="cl"><span class="w">        </span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 50</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="w">        </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 52</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">counts</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="w">            </span><span class="k">for</span><span class="w"> </span><span class="n">mat</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">pattern</span><span class="p">.</span><span class="n">find_iter</span><span class="p">(</span><span class="n">text</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="w">                </span><span class="kd">let</span><span class="w"> </span><span class="n">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">lowercase</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 55</span><span class="cl"><span class="w">                    </span><span class="n">mat</span><span class="p">.</span><span class="n">as_str</span><span class="p">().</span><span class="n">to_lowercase</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 56</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 57</span><span class="cl"><span class="w">                    </span><span class="n">mat</span><span class="p">.</span><span class="n">as_str</span><span class="p">().</span><span class="n">to_string</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 58</span><span class="cl"><span class="w">                </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 59</span><span class="cl"><span class="w">                </span><span class="o">*</span><span class="n">counts</span><span class="p">.</span><span class="n">entry</span><span class="p">(</span><span class="n">token</span><span class="p">).</span><span class="n">or_insert</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 60</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 61</span><span class="cl"><span class="w">            </span><span class="n">counts</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 62</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 63</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 64</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 65</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 66</span><span class="cl"><span class="w"></span><span class="c1">// 簡單的 BPE（Byte Pair Encoding）實現
</span></span></span><span class="line"><span class="ln"> 67</span><span class="cl"><span class="c1"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 68</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">SimpleBPE</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 69</span><span class="cl"><span class="w">    </span><span class="n">vocab</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="kt">u32</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 70</span><span class="cl"><span class="w">    </span><span class="n">merges</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="p">(</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">String</span><span class="p">)</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 71</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 73</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 74</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">SimpleBPE</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 75</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 76</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 77</span><span class="cl"><span class="w">        </span><span class="n">SimpleBPE</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 78</span><span class="cl"><span class="w">            </span><span class="n">vocab</span>: <span class="nc">HashMap</span>::<span class="n">new</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 79</span><span class="cl"><span class="w">            </span><span class="n">merges</span>: <span class="nb">Vec</span>::<span class="n">new</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 80</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 81</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 82</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 83</span><span class="cl"><span class="w">    </span><span class="sd">/// 訓練 BPE
</span></span></span><span class="line"><span class="ln"> 84</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">train</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">texts</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">vocab_size</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 85</span><span class="cl"><span class="w">        </span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 86</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 87</span><span class="cl"><span class="w">        </span><span class="n">py</span><span class="p">.</span><span class="n">allow_threads</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 88</span><span class="cl"><span class="w">            </span><span class="c1">// 初始化：每個字元是一個 token
</span></span></span><span class="line"><span class="ln"> 89</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">word_freqs</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 90</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 91</span><span class="cl"><span class="w">            </span><span class="k">for</span><span class="w"> </span><span class="n">text</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&amp;</span><span class="n">texts</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 92</span><span class="cl"><span class="w">                </span><span class="k">for</span><span class="w"> </span><span class="n">word</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">text</span><span class="p">.</span><span class="n">split_whitespace</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 93</span><span class="cl"><span class="w">                    </span><span class="kd">let</span><span class="w"> </span><span class="n">chars</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">word</span><span class="p">.</span><span class="n">chars</span><span class="p">().</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">c</span><span class="o">|</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">to_string</span><span class="p">()).</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 94</span><span class="cl"><span class="w">                    </span><span class="o">*</span><span class="n">word_freqs</span><span class="p">.</span><span class="n">entry</span><span class="p">(</span><span class="n">chars</span><span class="p">).</span><span class="n">or_insert</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 95</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 96</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 97</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 98</span><span class="cl"><span class="w">            </span><span class="c1">// 迭代合併最頻繁的 pair
</span></span></span><span class="line"><span class="ln"> 99</span><span class="cl"><span class="c1"></span><span class="w">            </span><span class="k">while</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">vocab</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">vocab_size</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">100</span><span class="cl"><span class="w">                </span><span class="c1">// 計算 pair 頻率
</span></span></span><span class="line"><span class="ln">101</span><span class="cl"><span class="c1"></span><span class="w">                </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">pair_freqs</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="p">(</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">String</span><span class="p">),</span><span class="w"> </span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">102</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">103</span><span class="cl"><span class="w">                </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">word</span><span class="p">,</span><span class="w"> </span><span class="n">freq</span><span class="p">)</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&amp;</span><span class="n">word_freqs</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">104</span><span class="cl"><span class="w">                    </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="n">word</span><span class="p">.</span><span class="n">len</span><span class="p">().</span><span class="n">saturating_sub</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">105</span><span class="cl"><span class="w">                        </span><span class="kd">let</span><span class="w"> </span><span class="n">pair</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clone</span><span class="p">(),</span><span class="w"> </span><span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">].</span><span class="n">clone</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">106</span><span class="cl"><span class="w">                        </span><span class="o">*</span><span class="n">pair_freqs</span><span class="p">.</span><span class="n">entry</span><span class="p">(</span><span class="n">pair</span><span class="p">).</span><span class="n">or_insert</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">freq</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">107</span><span class="cl"><span class="w">                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">108</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">109</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">110</span><span class="cl"><span class="w">                </span><span class="c1">// 找出最頻繁的 pair
</span></span></span><span class="line"><span class="ln">111</span><span class="cl"><span class="c1"></span><span class="w">                </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">((</span><span class="n">best_pair</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">))</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pair_freqs</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">max_by_key</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">freq</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">freq</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">112</span><span class="cl"><span class="w">                    </span><span class="kd">let</span><span class="w"> </span><span class="n">new_token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;</span><span class="si">{}{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">best_pair</span><span class="p">.</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">best_pair</span><span class="p">.</span><span class="mi">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">113</span><span class="cl"><span class="w">                    </span><span class="bp">self</span><span class="p">.</span><span class="n">merges</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">best_pair</span><span class="p">.</span><span class="n">clone</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">114</span><span class="cl"><span class="w">                    </span><span class="bp">self</span><span class="p">.</span><span class="n">vocab</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">new_token</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">vocab</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">u32</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">115</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">116</span><span class="cl"><span class="w">                    </span><span class="c1">// 更新 word_freqs
</span></span></span><span class="line"><span class="ln">117</span><span class="cl"><span class="c1"></span><span class="w">                    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">new_word_freqs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">118</span><span class="cl"><span class="w">                    </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">word</span><span class="p">,</span><span class="w"> </span><span class="n">freq</span><span class="p">)</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">word_freqs</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">119</span><span class="cl"><span class="w">                        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">new_word</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">120</span><span class="cl"><span class="w">                        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">121</span><span class="cl"><span class="w">                        </span><span class="k">while</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">word</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">122</span><span class="cl"><span class="w">                            </span><span class="k">if</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">word</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">best_pair</span><span class="p">.</span><span class="mi">0</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">best_pair</span><span class="p">.</span><span class="mi">1</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">123</span><span class="cl"><span class="w">                                </span><span class="n">new_word</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">new_token</span><span class="p">.</span><span class="n">clone</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">124</span><span class="cl"><span class="w">                                </span><span class="n">i</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">125</span><span class="cl"><span class="w">                            </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">126</span><span class="cl"><span class="w">                                </span><span class="n">new_word</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clone</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">127</span><span class="cl"><span class="w">                                </span><span class="n">i</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">128</span><span class="cl"><span class="w">                            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">129</span><span class="cl"><span class="w">                        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">130</span><span class="cl"><span class="w">                        </span><span class="o">*</span><span class="n">new_word_freqs</span><span class="p">.</span><span class="n">entry</span><span class="p">(</span><span class="n">new_word</span><span class="p">).</span><span class="n">or_insert</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">freq</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">131</span><span class="cl"><span class="w">                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">132</span><span class="cl"><span class="w">                    </span><span class="n">word_freqs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">new_word_freqs</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">133</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">134</span><span class="cl"><span class="w">                    </span><span class="k">break</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">135</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">136</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">137</span><span class="cl"><span class="w">        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">138</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">139</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">140</span><span class="cl"><span class="w">    </span><span class="sd">/// 編碼文字
</span></span></span><span class="line"><span class="ln">141</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">encode</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">text</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">u32</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">142</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">tokens</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">text</span><span class="p">.</span><span class="n">chars</span><span class="p">().</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">c</span><span class="o">|</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">to_string</span><span class="p">()).</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">143</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">144</span><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">merges</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">145</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">merged</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;</span><span class="si">{}{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">146</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">new_tokens</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">147</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">148</span><span class="cl"><span class="w">            </span><span class="k">while</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">tokens</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">149</span><span class="cl"><span class="w">                </span><span class="k">if</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">tokens</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="o">&amp;</span><span class="n">tokens</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="o">&amp;</span><span class="n">tokens</span><span class="p">[</span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">150</span><span class="cl"><span class="w">                    </span><span class="n">new_tokens</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">merged</span><span class="p">.</span><span class="n">clone</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">151</span><span class="cl"><span class="w">                    </span><span class="n">i</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">152</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">153</span><span class="cl"><span class="w">                    </span><span class="n">new_tokens</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">tokens</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clone</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">154</span><span class="cl"><span class="w">                    </span><span class="n">i</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">155</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">156</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">157</span><span class="cl"><span class="w">            </span><span class="n">tokens</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">new_tokens</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">158</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">159</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">160</span><span class="cl"><span class="w">        </span><span class="n">tokens</span><span class="w">
</span></span></span><span class="line"><span class="ln">161</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">162</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">filter_map</span><span class="p">(</span><span class="o">|</span><span class="n">t</span><span class="o">|</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">vocab</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">t</span><span class="p">).</span><span class="n">copied</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln">163</span><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">164</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">165</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">166</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">167</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">168</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">169</span><span class="cl"><span class="w"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">170</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">fast_tokenizer</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">171</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">Tokenizer</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">172</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">SimpleBPE</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">173</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">174</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="使用範例">使用範例</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">fast_tokenizer</span> <span class="kn">import</span> <span class="n">Tokenizer</span><span class="p">,</span> <span class="n">SimpleBPE</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"># 基本 tokenization</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">tokenizer</span> <span class="o">=</span> <span class="n">Tokenizer</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;\w+&#34;</span><span class="p">,</span> <span class="n">lowercase</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">text</span> <span class="o">=</span> <span class="s2">&#34;Hello, World! This is a test.&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">tokens</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">tokenize</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">tokens</span><span class="p">)</span>  <span class="c1"># [&#39;hello&#39;, &#39;world&#39;, &#39;this&#39;, &#39;is&#39;, &#39;a&#39;, &#39;test&#39;]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 批次處理</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">texts</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;First sentence.&#34;</span><span class="p">,</span> <span class="s2">&#34;Second sentence.&#34;</span><span class="p">,</span> <span class="s2">&#34;Third one.&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">batch_tokens</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">tokenize_batch</span><span class="p">(</span><span class="n">texts</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">batch_tokens</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"># 詞頻統計</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">counts</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">count_tokens</span><span class="p">(</span><span class="s2">&#34;the cat sat on the mat&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">counts</span><span class="p">)</span>  <span class="c1"># {&#39;the&#39;: 2, &#39;cat&#39;: 1, &#39;sat&#39;: 1, &#39;on&#39;: 1, &#39;mat&#39;: 1}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"># BPE 訓練</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">bpe</span> <span class="o">=</span> <span class="n">SimpleBPE</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">corpus</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;hello world&#34;</span><span class="p">,</span> <span class="s2">&#34;hello there&#34;</span><span class="p">,</span> <span class="s2">&#34;world peace&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">bpe</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="n">corpus</span><span class="p">,</span> <span class="n">vocab_size</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">encoded</span> <span class="o">=</span> <span class="n">bpe</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&#34;hello world&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">encoded</span><span class="p">)</span></span></span></code></pre></div><hr>
<h2 id="案例三資料驗證pydantic-風格驗證器">【案例三】資料驗證：Pydantic 風格驗證器</h2>
<h3 id="需求分析-2">需求分析</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">場景：API 需要驗證大量輸入資料
</span></span><span class="line"><span class="ln">2</span><span class="cl">問題：純 Python 驗證太慢（Pydantic v1 的問題）
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">實現目標：
</span></span><span class="line"><span class="ln">5</span><span class="cl">├── 型別檢查
</span></span><span class="line"><span class="ln">6</span><span class="cl">├── 範圍驗證
</span></span><span class="line"><span class="ln">7</span><span class="cl">├── 自訂驗證函式
</span></span><span class="line"><span class="ln">8</span><span class="cl">└── 清晰的錯誤訊息</span></span></code></pre></div><h3 id="rust-實現-2">Rust 實現</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln">  1</span><span class="cl"><span class="c1">// src/lib.rs
</span></span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="c1"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">exceptions</span>::<span class="n">PyValueError</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  4</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="w"></span><span class="c1">// 驗證錯誤
</span></span></span><span class="line"><span class="ln">  7</span><span class="cl"><span class="c1"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="w"></span><span class="cp">#[derive(Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="w">    </span><span class="n">field</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(get)]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 13</span><span class="cl"><span class="w">    </span><span class="n">message</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 14</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 15</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 17</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 18</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">__repr__</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 19</span><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;ValidationError(field=&#39;</span><span class="si">{}</span><span class="s">&#39;, message=&#39;</span><span class="si">{}</span><span class="s">&#39;)&#34;</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">field</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">message</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 20</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 21</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 22</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 23</span><span class="cl"><span class="w"></span><span class="c1">// 欄位驗證器
</span></span></span><span class="line"><span class="ln"> 24</span><span class="cl"><span class="c1"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 25</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Field</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 26</span><span class="cl"><span class="w">    </span><span class="n">name</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 27</span><span class="cl"><span class="w">    </span><span class="n">field_type</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="w">    </span><span class="n">required</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 29</span><span class="cl"><span class="w">    </span><span class="n">min_value</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="w">    </span><span class="n">max_value</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 31</span><span class="cl"><span class="w">    </span><span class="n">min_length</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 32</span><span class="cl"><span class="w">    </span><span class="n">max_length</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 33</span><span class="cl"><span class="w">    </span><span class="n">pattern</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="n">regex</span>::<span class="n">Regex</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 35</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 36</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 37</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Field</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 38</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 39</span><span class="cl"><span class="w">    </span><span class="cp">#[pyo3(signature = (name, field_type, required=true, min_value=None, max_value=None, min_length=None, max_length=None, pattern=None))]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="w">        </span><span class="n">name</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 42</span><span class="cl"><span class="w">        </span><span class="n">field_type</span>: <span class="nb">String</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 43</span><span class="cl"><span class="w">        </span><span class="n">required</span>: <span class="kt">bool</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 44</span><span class="cl"><span class="w">        </span><span class="n">min_value</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 45</span><span class="cl"><span class="w">        </span><span class="n">max_value</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 46</span><span class="cl"><span class="w">        </span><span class="n">min_length</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 47</span><span class="cl"><span class="w">        </span><span class="n">max_length</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 48</span><span class="cl"><span class="w">        </span><span class="n">pattern</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 49</span><span class="cl"><span class="w">    </span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 50</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">pattern</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">pattern</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="w">            </span><span class="nb">Some</span><span class="p">(</span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">regex</span>::<span class="n">Regex</span>::<span class="n">new</span><span class="p">(</span><span class="o">&amp;</span><span class="n">p</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 52</span><span class="cl"><span class="w">                </span><span class="p">.</span><span class="n">map_err</span><span class="p">(</span><span class="o">|</span><span class="n">e</span><span class="o">|</span><span class="w"> </span><span class="n">PyValueError</span>::<span class="n">new_err</span><span class="p">(</span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;無效的正規表達式: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)))</span><span class="o">?</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="w">            </span><span class="nb">None</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nb">None</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="w">        </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 55</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 56</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">Field</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 57</span><span class="cl"><span class="w">            </span><span class="n">name</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 58</span><span class="cl"><span class="w">            </span><span class="n">field_type</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 59</span><span class="cl"><span class="w">            </span><span class="n">required</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 60</span><span class="cl"><span class="w">            </span><span class="n">min_value</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 61</span><span class="cl"><span class="w">            </span><span class="n">max_value</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 62</span><span class="cl"><span class="w">            </span><span class="n">min_length</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 63</span><span class="cl"><span class="w">            </span><span class="n">max_length</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 64</span><span class="cl"><span class="w">            </span><span class="n">pattern</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 65</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 66</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 67</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 68</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 69</span><span class="cl"><span class="w"></span><span class="c1">// Schema 驗證器
</span></span></span><span class="line"><span class="ln"> 70</span><span class="cl"><span class="c1"></span><span class="cp">#[pyclass]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 71</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Schema</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="w">    </span><span class="n">fields</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Field</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 73</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 74</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 75</span><span class="cl"><span class="w"></span><span class="cp">#[pymethods]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 76</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Schema</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 77</span><span class="cl"><span class="w">    </span><span class="cp">#[new]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 78</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">fields</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Py</span><span class="o">&lt;</span><span class="n">Field</span><span class="o">&gt;&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="bp">Self</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 79</span><span class="cl"><span class="w">        </span><span class="n">Python</span>::<span class="n">with_gil</span><span class="p">(</span><span class="o">|</span><span class="n">py</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 80</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">fields</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Field</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fields</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 81</span><span class="cl"><span class="w">                </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 82</span><span class="cl"><span class="w">                </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">f</span><span class="o">|</span><span class="w"> </span><span class="n">f</span><span class="p">.</span><span class="n">borrow</span><span class="p">(</span><span class="n">py</span><span class="p">).</span><span class="n">clone</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 83</span><span class="cl"><span class="w">                </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 84</span><span class="cl"><span class="w">            </span><span class="nb">Ok</span><span class="p">(</span><span class="n">Schema</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">fields</span><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 85</span><span class="cl"><span class="w">        </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 86</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 87</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 88</span><span class="cl"><span class="w">    </span><span class="sd">/// 驗證單一物件
</span></span></span><span class="line"><span class="ln"> 89</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">validate</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">data</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyDict</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">ValidationError</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 90</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">errors</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 91</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 92</span><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">field</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">fields</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 93</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">get_item</span><span class="p">(</span><span class="o">&amp;</span><span class="n">field</span><span class="p">.</span><span class="n">name</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 94</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 95</span><span class="cl"><span class="w">            </span><span class="k">match</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 96</span><span class="cl"><span class="w">                </span><span class="nb">None</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 97</span><span class="cl"><span class="w">                    </span><span class="k">if</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">required</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 98</span><span class="cl"><span class="w">                        </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 99</span><span class="cl"><span class="w">                            </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">100</span><span class="cl"><span class="w">                            </span><span class="n">message</span>: <span class="s">&#34;此欄位為必填&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">101</span><span class="cl"><span class="w">                        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">102</span><span class="cl"><span class="w">                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">103</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">104</span><span class="cl"><span class="w">                </span><span class="nb">Some</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">105</span><span class="cl"><span class="w">                    </span><span class="c1">// 型別檢查
</span></span></span><span class="line"><span class="ln">106</span><span class="cl"><span class="c1"></span><span class="w">                    </span><span class="k">match</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">field_type</span><span class="p">.</span><span class="n">as_str</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">107</span><span class="cl"><span class="w">                        </span><span class="s">&#34;int&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">108</span><span class="cl"><span class="w">                            </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">num</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">extract</span>::<span class="o">&lt;</span><span class="kt">i64</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">109</span><span class="cl"><span class="w">                                </span><span class="c1">// 範圍檢查
</span></span></span><span class="line"><span class="ln">110</span><span class="cl"><span class="c1"></span><span class="w">                                </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">min</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">min_value</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">111</span><span class="cl"><span class="w">                                    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">num</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">f64</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">min</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">112</span><span class="cl"><span class="w">                                        </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">113</span><span class="cl"><span class="w">                                            </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">114</span><span class="cl"><span class="w">                                            </span><span class="n">message</span>: <span class="nc">format</span><span class="o">!</span><span class="p">(</span><span class="s">&#34;值必須 &gt;= {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">min</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">115</span><span class="cl"><span class="w">                                        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">116</span><span class="cl"><span class="w">                                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">117</span><span class="cl"><span class="w">                                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">118</span><span class="cl"><span class="w">                                </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">max</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">max_value</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">119</span><span class="cl"><span class="w">                                    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">num</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">f64</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">max</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">120</span><span class="cl"><span class="w">                                        </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">121</span><span class="cl"><span class="w">                                            </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">122</span><span class="cl"><span class="w">                                            </span><span class="n">message</span>: <span class="nc">format</span><span class="o">!</span><span class="p">(</span><span class="s">&#34;值必須 &lt;= {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">max</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">123</span><span class="cl"><span class="w">                                        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">124</span><span class="cl"><span class="w">                                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">125</span><span class="cl"><span class="w">                                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">126</span><span class="cl"><span class="w">                            </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">127</span><span class="cl"><span class="w">                                </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">128</span><span class="cl"><span class="w">                                    </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">129</span><span class="cl"><span class="w">                                    </span><span class="n">message</span>: <span class="s">&#34;必須是整數&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">130</span><span class="cl"><span class="w">                                </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">131</span><span class="cl"><span class="w">                            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">132</span><span class="cl"><span class="w">                        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">133</span><span class="cl"><span class="w">                        </span><span class="s">&#34;float&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">134</span><span class="cl"><span class="w">                            </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">num</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">extract</span>::<span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">135</span><span class="cl"><span class="w">                                </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">min</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">min_value</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">136</span><span class="cl"><span class="w">                                    </span><span class="k">if</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">min</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">137</span><span class="cl"><span class="w">                                        </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">138</span><span class="cl"><span class="w">                                            </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">139</span><span class="cl"><span class="w">                                            </span><span class="n">message</span>: <span class="nc">format</span><span class="o">!</span><span class="p">(</span><span class="s">&#34;值必須 &gt;= {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">min</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">140</span><span class="cl"><span class="w">                                        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">141</span><span class="cl"><span class="w">                                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">142</span><span class="cl"><span class="w">                                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">143</span><span class="cl"><span class="w">                                </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">max</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">max_value</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">144</span><span class="cl"><span class="w">                                    </span><span class="k">if</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">max</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">145</span><span class="cl"><span class="w">                                        </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">146</span><span class="cl"><span class="w">                                            </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">147</span><span class="cl"><span class="w">                                            </span><span class="n">message</span>: <span class="nc">format</span><span class="o">!</span><span class="p">(</span><span class="s">&#34;值必須 &lt;= {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">max</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">148</span><span class="cl"><span class="w">                                        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">149</span><span class="cl"><span class="w">                                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">150</span><span class="cl"><span class="w">                                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">151</span><span class="cl"><span class="w">                            </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">152</span><span class="cl"><span class="w">                                </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">153</span><span class="cl"><span class="w">                                    </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">154</span><span class="cl"><span class="w">                                    </span><span class="n">message</span>: <span class="s">&#34;必須是浮點數&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">155</span><span class="cl"><span class="w">                                </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">156</span><span class="cl"><span class="w">                            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">157</span><span class="cl"><span class="w">                        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">158</span><span class="cl"><span class="w">                        </span><span class="s">&#34;str&#34;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">159</span><span class="cl"><span class="w">                            </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">extract</span>::<span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">160</span><span class="cl"><span class="w">                                </span><span class="c1">// 長度檢查
</span></span></span><span class="line"><span class="ln">161</span><span class="cl"><span class="c1"></span><span class="w">                                </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">min_len</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">min_length</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">162</span><span class="cl"><span class="w">                                    </span><span class="k">if</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">min_len</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">163</span><span class="cl"><span class="w">                                        </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">164</span><span class="cl"><span class="w">                                            </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">165</span><span class="cl"><span class="w">                                            </span><span class="n">message</span>: <span class="nc">format</span><span class="o">!</span><span class="p">(</span><span class="s">&#34;長度必須 &gt;= {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">min_len</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">166</span><span class="cl"><span class="w">                                        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">167</span><span class="cl"><span class="w">                                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">168</span><span class="cl"><span class="w">                                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">169</span><span class="cl"><span class="w">                                </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">max_len</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">max_length</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">170</span><span class="cl"><span class="w">                                    </span><span class="k">if</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">max_len</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">171</span><span class="cl"><span class="w">                                        </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">172</span><span class="cl"><span class="w">                                            </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">173</span><span class="cl"><span class="w">                                            </span><span class="n">message</span>: <span class="nc">format</span><span class="o">!</span><span class="p">(</span><span class="s">&#34;長度必須 &lt;= {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">max_len</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="ln">174</span><span class="cl"><span class="w">                                        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">175</span><span class="cl"><span class="w">                                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">176</span><span class="cl"><span class="w">                                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">177</span><span class="cl"><span class="w">                                </span><span class="c1">// 正規表達式檢查
</span></span></span><span class="line"><span class="ln">178</span><span class="cl"><span class="c1"></span><span class="w">                                </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="k">ref</span><span class="w"> </span><span class="n">pattern</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">field</span><span class="p">.</span><span class="n">pattern</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">179</span><span class="cl"><span class="w">                                    </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="n">pattern</span><span class="p">.</span><span class="n">is_match</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">180</span><span class="cl"><span class="w">                                        </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">181</span><span class="cl"><span class="w">                                            </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">182</span><span class="cl"><span class="w">                                            </span><span class="n">message</span>: <span class="s">&#34;格式不符合要求&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">183</span><span class="cl"><span class="w">                                        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">184</span><span class="cl"><span class="w">                                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">185</span><span class="cl"><span class="w">                                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">186</span><span class="cl"><span class="w">                            </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">187</span><span class="cl"><span class="w">                                </span><span class="n">errors</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ValidationError</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">188</span><span class="cl"><span class="w">                                    </span><span class="n">field</span>: <span class="nc">field</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="n">clone</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">189</span><span class="cl"><span class="w">                                    </span><span class="n">message</span>: <span class="s">&#34;必須是字串&#34;</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="ln">190</span><span class="cl"><span class="w">                                </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">191</span><span class="cl"><span class="w">                            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">192</span><span class="cl"><span class="w">                        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">193</span><span class="cl"><span class="w">                        </span><span class="n">_</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="ln">194</span><span class="cl"><span class="w">                    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">195</span><span class="cl"><span class="w">                </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">196</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">197</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">198</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">199</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">errors</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">200</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">201</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">202</span><span class="cl"><span class="w">    </span><span class="sd">/// 批次驗證
</span></span></span><span class="line"><span class="ln">203</span><span class="cl"><span class="sd"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">validate_batch</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">py</span>: <span class="nc">Python</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">data_list</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyDict</span><span class="o">&gt;&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">ValidationError</span><span class="o">&gt;&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">204</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">results</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">205</span><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">data_list</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">206</span><span class="cl"><span class="w">            </span><span class="n">results</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">validate</span><span class="p">(</span><span class="n">py</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">data</span><span class="p">)</span><span class="o">?</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">207</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">208</span><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">results</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">209</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">210</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">211</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">212</span><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">pyo3</span>::<span class="n">types</span>::<span class="n">PyDict</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">213</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">214</span><span class="cl"><span class="w"></span><span class="cp">#[pymodule]</span><span class="w">
</span></span></span><span class="line"><span class="ln">215</span><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">fast_validator</span><span class="p">(</span><span class="n">m</span>: <span class="kp">&amp;</span><span class="nc">Bound</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="p">,</span><span class="w"> </span><span class="n">PyModule</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PyResult</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">216</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">Field</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">217</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">Schema</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">218</span><span class="cl"><span class="w">    </span><span class="n">m</span><span class="p">.</span><span class="n">add_class</span>::<span class="o">&lt;</span><span class="n">ValidationError</span><span class="o">&gt;</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">219</span><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="ln">220</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><h3 id="使用範例-1">使用範例</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">fast_validator</span> <span class="kn">import</span> <span class="n">Field</span><span class="p">,</span> <span class="n">Schema</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"># 定義 schema</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">schema</span> <span class="o">=</span> <span class="n">Schema</span><span class="p">([</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">Field</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">,</span> <span class="s2">&#34;str&#34;</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">min_length</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">Field</span><span class="p">(</span><span class="s2">&#34;age&#34;</span><span class="p">,</span> <span class="s2">&#34;int&#34;</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">min_value</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">max_value</span><span class="o">=</span><span class="mi">150</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">Field</span><span class="p">(</span><span class="s2">&#34;email&#34;</span><span class="p">,</span> <span class="s2">&#34;str&#34;</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">pattern</span><span class="o">=</span><span class="sa">r</span><span class="s2">&#34;^[\w\.-]+@[\w\.-]+\.\w+$&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">Field</span><span class="p">(</span><span class="s2">&#34;score&#34;</span><span class="p">,</span> <span class="s2">&#34;float&#34;</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">min_value</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">max_value</span><span class="o">=</span><span class="mi">100</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">])</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># 驗證資料</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Alice&#34;</span><span class="p">,</span> <span class="s2">&#34;age&#34;</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span> <span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;alice@example.com&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">errors</span> <span class="o">=</span> <span class="n">schema</span><span class="o">.</span><span class="n">validate</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">errors</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">e</span><span class="o">.</span><span class="n">field</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="o">.</span><span class="n">message</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;驗證通過&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c1"># 無效資料</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">invalid_data</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;age&#34;</span><span class="p">:</span> <span class="o">-</span><span class="mi">5</span><span class="p">,</span> <span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;invalid&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">errors</span> <span class="o">=</span> <span class="n">schema</span><span class="o">.</span><span class="n">validate</span><span class="p">(</span><span class="n">invalid_data</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">errors</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">e</span><span class="o">.</span><span class="n">field</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="o">.</span><span class="n">message</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1"># name: 長度必須 &gt;= 1</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"># age: 值必須 &gt;= 0</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="c1"># email: 格式不符合要求</span></span></span></code></pre></div><hr>
<h2 id="總結何時使用-rust">【總結】何時使用 Rust</h2>
<h3 id="決策清單">決策清單</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">應該使用 Rust：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">1. 效能瓶頸明確
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">   □ profiler 顯示特定函式占用大量時間
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">   □ 純 Python 優化已到極限
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">   □ 現有 C 擴展不滿足需求
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">2. 資料處理需求
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   □ 大量數值計算
</span></span><span class="line"><span class="ln">10</span><span class="cl">   □ 頻繁的字串處理
</span></span><span class="line"><span class="ln">11</span><span class="cl">   □ 需要並行處理
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">3. 安全性要求
</span></span><span class="line"><span class="ln">14</span><span class="cl">   □ 處理不可信的輸入
</span></span><span class="line"><span class="ln">15</span><span class="cl">   □ 需要避免記憶體錯誤
</span></span><span class="line"><span class="ln">16</span><span class="cl">   □ 長期運行的服務
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">4. 跨平台需求
</span></span><span class="line"><span class="ln">19</span><span class="cl">   □ 需要支援多個作業系統
</span></span><span class="line"><span class="ln">20</span><span class="cl">   □ 需要支援多個 Python 版本
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl">可能不需要 Rust：
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl">1. 效能不是主要瓶頸
</span></span><span class="line"><span class="ln">25</span><span class="cl">2. 團隊沒有 Rust 經驗且時間緊迫
</span></span><span class="line"><span class="ln">26</span><span class="cl">3. 專案規模小且不會長期維護
</span></span><span class="line"><span class="ln">27</span><span class="cl">4. 可以用現有函式庫解決</span></span></code></pre></div><h3 id="最佳實踐">最佳實踐</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">1. 設計階段
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">   ├── 明確定義 Python/Rust 邊界
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">   ├── 最小化跨語言呼叫次數
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">   ├── 使用批次處理減少開銷
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">   └── 設計清晰的錯誤處理
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">2. 開發階段
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">   ├── 先用 Python 原型驗證邏輯
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   ├── 逐步將瓶頸移到 Rust
</span></span><span class="line"><span class="ln">10</span><span class="cl">   ├── 完善的測試覆蓋
</span></span><span class="line"><span class="ln">11</span><span class="cl">   └── 使用 maturin develop 快速迭代
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">3. 發布階段
</span></span><span class="line"><span class="ln">14</span><span class="cl">   ├── 使用 CI/CD 自動建構 wheel
</span></span><span class="line"><span class="ln">15</span><span class="cl">   ├── 支援主流 Python 版本
</span></span><span class="line"><span class="ln">16</span><span class="cl">   ├── 提供 fallback 純 Python 實現
</span></span><span class="line"><span class="ln">17</span><span class="cl">   └── 清楚的安裝文件</span></span></code></pre></div><hr>
<h2 id="思考題">思考題</h2>
<ol>
<li>在設計 Rust 擴展的 API 時，如何平衡效能和易用性？</li>
<li>如何處理 Rust 函式庫沒有 Python 綁定的情況？</li>
<li>在什麼情況下，應該用 Cython 而不是 Rust？</li>
</ol>
<h2 id="實作練習">實作練習</h2>
<ol>
<li>選擇一個你常用的純 Python 函式，用 Rust 重寫並比較效能</li>
<li>分析 <a href="https://github.com/pola-rs/polars">Polars</a> 的原始碼結構，理解大型 Rust Python 專案的組織方式</li>
<li>實現一個簡單的 JSON parser，比較與 Python <code>json</code> 模組的效能差異</li>
</ol>
<h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://github.com/pola-rs/polars">Polars 原始碼</a></li>
<li><a href="https://github.com/astral-sh/ruff">Ruff 原始碼</a></li>
<li><a href="https://github.com/openai/tiktoken">tiktoken 原始碼</a></li>
<li><a href="https://github.com/pydantic/pydantic-core">pydantic-core 原始碼</a></li>
</ul>
<hr>
<p><em>上一章：<a href="/blog/python-advanced/06-rust-extensions/maturin-workflow/" data-link-title="5.3 Maturin 開發流程" data-link-desc="使用 Maturin 建構和發布 Rust Python 套件">Maturin 開發流程</a></em>
<em>下一模組：<a href="/blog/python-advanced/07-packaging/" data-link-title="模組七：打包與發布" data-link-desc="學習現代 Python 套件的打包與發布流程">模組六：打包與發布</a></em></p>
]]></content:encoded></item><item><title>模組六：用 Rust 擴展 Python</title><link>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/</link><pubDate>Tue, 20 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/</guid><description>&lt;p>本模組介紹如何使用 Rust 擴展 Python，結合 Rust 的記憶體安全與高效能。&lt;/p>
&lt;h2 id="為什麼選擇-rust">為什麼選擇 Rust？&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>記憶體安全&lt;/strong>：沒有空指標、沒有資料競爭&lt;/li>
&lt;li>&lt;strong>零成本抽象&lt;/strong>：高階語法，底層效能&lt;/li>
&lt;li>&lt;strong>現代工具鏈&lt;/strong>：Cargo 生態系統的便利性&lt;/li>
&lt;/ul>
&lt;h2 id="章節列表">章節列表&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>章節&lt;/th>
 &lt;th>主題&lt;/th>
 &lt;th>關鍵收穫&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/why-rust/" data-link-title="5.1 為什麼選擇 Rust？" data-link-desc="比較 Rust 與 C/C&amp;#43;&amp;#43; 作為 Python 擴展語言">6.1&lt;/a>&lt;/td>
 &lt;td>為什麼選擇 Rust？&lt;/td>
 &lt;td>Rust vs C/C++ 的比較&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/pyo3-basics/" data-link-title="5.2 PyO3 基礎" data-link-desc="使用 PyO3 建立 Rust 與 Python 的綁定">6.2&lt;/a>&lt;/td>
 &lt;td>PyO3 基礎&lt;/td>
 &lt;td>Rust 的 Python 綁定&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/maturin-workflow/" data-link-title="5.3 Maturin 開發流程" data-link-desc="使用 Maturin 建構和發布 Rust Python 套件">6.3&lt;/a>&lt;/td>
 &lt;td>Maturin 開發流程&lt;/td>
 &lt;td>建構與發布工具&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/real-world-examples/" data-link-title="5.4 實戰案例分析" data-link-desc="分析知名 Python 專案如何使用 Rust">6.4&lt;/a>&lt;/td>
 &lt;td>實戰案例分析&lt;/td>
 &lt;td>知名專案的 Rust 應用&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="使用-rust-的知名-python-套件">使用 Rust 的知名 Python 套件&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>tiktoken&lt;/strong>（OpenAI）：快速的 tokenizer&lt;/li>
&lt;li>&lt;strong>tokenizers&lt;/strong>（Hugging Face）：NLP tokenizer&lt;/li>
&lt;li>&lt;strong>polars&lt;/strong>：高效能 DataFrame 函式庫&lt;/li>
&lt;li>&lt;strong>pydantic-core&lt;/strong>：Pydantic v2 的核心&lt;/li>
&lt;/ul>
&lt;h2 id="先備知識">先備知識&lt;/h2>
&lt;ul>
&lt;li>進階系列 &lt;a href="https://tarrragon.github.io/blog/python-advanced/04-cpython-internals/" data-link-title="模組四：CPython 內部機制" data-link-desc="深入 CPython 直譯器，理解 Python 如何運作">模組四：CPython 內部機制&lt;/a>&lt;/li>
&lt;li>基本的 Rust 語言知識（所有權、生命週期、Result/Option）&lt;/li>
&lt;/ul>
&lt;h2 id="學習時間">學習時間&lt;/h2>
&lt;p>每章節約 45-60 分鐘，全模組約 3-4 小時&lt;/p>
&lt;hr>
&lt;p>&lt;em>上一模組：&lt;a href="https://tarrragon.github.io/blog/python-advanced/05-c-extensions/" data-link-title="模組五：用 C 擴展 Python" data-link-desc="學習使用 ctypes、cffi、Cython、pybind11 擴展 Python">模組五：用 C 擴展 Python&lt;/a>&lt;/em>
&lt;em>下一模組：&lt;a href="https://tarrragon.github.io/blog/python-advanced/07-packaging/" data-link-title="模組七：打包與發布" data-link-desc="學習現代 Python 套件的打包與發布流程">模組七：打包與發布&lt;/a>&lt;/em>&lt;/p></description><content:encoded><![CDATA[<p>本模組介紹如何使用 Rust 擴展 Python，結合 Rust 的記憶體安全與高效能。</p>
<h2 id="為什麼選擇-rust">為什麼選擇 Rust？</h2>
<ul>
<li><strong>記憶體安全</strong>：沒有空指標、沒有資料競爭</li>
<li><strong>零成本抽象</strong>：高階語法，底層效能</li>
<li><strong>現代工具鏈</strong>：Cargo 生態系統的便利性</li>
</ul>
<h2 id="章節列表">章節列表</h2>
<table>
  <thead>
      <tr>
          <th>章節</th>
          <th>主題</th>
          <th>關鍵收穫</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/python-advanced/06-rust-extensions/why-rust/" data-link-title="5.1 為什麼選擇 Rust？" data-link-desc="比較 Rust 與 C/C&#43;&#43; 作為 Python 擴展語言">6.1</a></td>
          <td>為什麼選擇 Rust？</td>
          <td>Rust vs C/C++ 的比較</td>
      </tr>
      <tr>
          <td><a href="/blog/python-advanced/06-rust-extensions/pyo3-basics/" data-link-title="5.2 PyO3 基礎" data-link-desc="使用 PyO3 建立 Rust 與 Python 的綁定">6.2</a></td>
          <td>PyO3 基礎</td>
          <td>Rust 的 Python 綁定</td>
      </tr>
      <tr>
          <td><a href="/blog/python-advanced/06-rust-extensions/maturin-workflow/" data-link-title="5.3 Maturin 開發流程" data-link-desc="使用 Maturin 建構和發布 Rust Python 套件">6.3</a></td>
          <td>Maturin 開發流程</td>
          <td>建構與發布工具</td>
      </tr>
      <tr>
          <td><a href="/blog/python-advanced/06-rust-extensions/real-world-examples/" data-link-title="5.4 實戰案例分析" data-link-desc="分析知名 Python 專案如何使用 Rust">6.4</a></td>
          <td>實戰案例分析</td>
          <td>知名專案的 Rust 應用</td>
      </tr>
  </tbody>
</table>
<h2 id="使用-rust-的知名-python-套件">使用 Rust 的知名 Python 套件</h2>
<ul>
<li><strong>tiktoken</strong>（OpenAI）：快速的 tokenizer</li>
<li><strong>tokenizers</strong>（Hugging Face）：NLP tokenizer</li>
<li><strong>polars</strong>：高效能 DataFrame 函式庫</li>
<li><strong>pydantic-core</strong>：Pydantic v2 的核心</li>
</ul>
<h2 id="先備知識">先備知識</h2>
<ul>
<li>進階系列 <a href="/blog/python-advanced/04-cpython-internals/" data-link-title="模組四：CPython 內部機制" data-link-desc="深入 CPython 直譯器，理解 Python 如何運作">模組四：CPython 內部機制</a></li>
<li>基本的 Rust 語言知識（所有權、生命週期、Result/Option）</li>
</ul>
<h2 id="學習時間">學習時間</h2>
<p>每章節約 45-60 分鐘，全模組約 3-4 小時</p>
<hr>
<p><em>上一模組：<a href="/blog/python-advanced/05-c-extensions/" data-link-title="模組五：用 C 擴展 Python" data-link-desc="學習使用 ctypes、cffi、Cython、pybind11 擴展 Python">模組五：用 C 擴展 Python</a></em>
<em>下一模組：<a href="/blog/python-advanced/07-packaging/" data-link-title="模組七：打包與發布" data-link-desc="學習現代 Python 套件的打包與發布流程">模組七：打包與發布</a></em></p>
]]></content:encoded></item><item><title>案例研究</title><link>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/</guid><description>&lt;p>本節收錄基於 &lt;code>.claude/lib&lt;/code> 實際程式碼的案例研究，展示如何用 PyO3 和 Rust 加速 Python 程式碼。&lt;/p>
&lt;h2 id="案例列表">案例列表&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>案例&lt;/th>
 &lt;th>素材&lt;/th>
 &lt;th>學習重點&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/pyo3-parser/" data-link-title="案例：PyO3 文字解析" data-link-desc="用 PyO3 和 Rust 實現高效能的 Markdown 連結解析器">PyO3 文字解析&lt;/a>&lt;/td>
 &lt;td>markdown_link_checker.py&lt;/td>
 &lt;td>PyO3 基礎、Maturin 建置&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/python-advanced/06-rust-extensions/case-studies/rust-regex/" data-link-title="案例：Rust 正則表達式" data-link-desc="用 Rust regex crate 加速 Hook 驗證器的模式匹配">Rust 正則表達式&lt;/a>&lt;/td>
 &lt;td>hook_validator.py&lt;/td>
 &lt;td>regex crate、效能比較&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="學習路徑">學習路徑&lt;/h2>
&lt;p>建議先完成本模組的理論章節，再閱讀案例研究：&lt;/p>
&lt;ol>
&lt;li>理解 Rust 基礎語法&lt;/li>
&lt;li>學習 PyO3 bindings&lt;/li>
&lt;li>通過案例實踐 Rust 加速&lt;/li>
&lt;/ol></description><content:encoded><![CDATA[<p>本節收錄基於 <code>.claude/lib</code> 實際程式碼的案例研究，展示如何用 PyO3 和 Rust 加速 Python 程式碼。</p>
<h2 id="案例列表">案例列表</h2>
<table>
  <thead>
      <tr>
          <th>案例</th>
          <th>素材</th>
          <th>學習重點</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/python-advanced/06-rust-extensions/case-studies/pyo3-parser/" data-link-title="案例：PyO3 文字解析" data-link-desc="用 PyO3 和 Rust 實現高效能的 Markdown 連結解析器">PyO3 文字解析</a></td>
          <td>markdown_link_checker.py</td>
          <td>PyO3 基礎、Maturin 建置</td>
      </tr>
      <tr>
          <td><a href="/blog/python-advanced/06-rust-extensions/case-studies/rust-regex/" data-link-title="案例：Rust 正則表達式" data-link-desc="用 Rust regex crate 加速 Hook 驗證器的模式匹配">Rust 正則表達式</a></td>
          <td>hook_validator.py</td>
          <td>regex crate、效能比較</td>
      </tr>
  </tbody>
</table>
<h2 id="學習路徑">學習路徑</h2>
<p>建議先完成本模組的理論章節，再閱讀案例研究：</p>
<ol>
<li>理解 Rust 基礎語法</li>
<li>學習 PyO3 bindings</li>
<li>通過案例實踐 Rust 加速</li>
</ol>
]]></content:encoded></item></channel></rss>