本文為轉載摘要,完整版請移步:
https://mp.weixin.qq.com/s/YT_HNFDCQ_IyocvBkRNJnA
以下為譯文:
大約一年前,我發布了一個名為inline-python(https://crates.io/crates/inline-python)的Rust類庫,它允許大家使用python!{ .. }宏輕松地將一些Python混合到Rust代碼中。在本系列中,我將從頭展示開發此類庫的過程。
-1-
預覽
如果不熟悉inline-python類庫,你可以執行以下操作:
fn main() {
let who = "world";
let n = 5;
python! {
for i in range('n):
print(i, "Hello", 'who)
print("Goodbye")
}
}
它允許你將Python代碼直接嵌入Rust代碼行之間,甚至直接在Python代碼中使用Rust變量。
我們將從一個比這個簡單得多的案例開始,然後逐步努力以達到這個結果(甚至更多!)。
-2-
運行Python代碼
首先,讓我們看一下如何在Rust中運行Python代碼。讓我們嘗試使第一個簡單的示例生效:
fn main() {
println!("Hello ...");
run_python("print(\"... World!\")");
}
我們可以使用std::process::命令來運行python可執行文件並傳遞python代碼,從而實現run_python,但如果我們希望能夠定義和讀回Python變量,那麼最好從使用PyO3庫開始。
PyO3為我們提供了Python的Rust綁定。它很好地包裝了Python C API,使我們可以直接在Rust中與各種Python對象交互。(甚至在Rust中編寫Python庫,但這是另一個主題。)
它的Python::run 功能完全符合我們的需求。它將Python代碼作為&str,並允許我們使用兩個可選的PyDicts 來定義范圍內的任何變量。讓我們試一試吧:
fn run_python(code: &str) {
let py = pyo3::Python::acquire_gil(); // Acquire the 'global interpreter lock', as Python is not thread-safe.
py.python().run(code, None, None).unwrap(); // No locals, no globals.
}
$ cargo run
Compiling scratchpad v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 0.29s
Running `target/debug/scratchpad`
Hello ...
... World!
看,這就成功了!
-3-
基於規則的宏
在字符串中編寫Python不是最便捷的方法,所以我們嘗試改進它。宏允許我們在Rust中自定義語法,所以讓我們嘗試一下:
fn main() {
println!("Hello ...");
python! {
print("... World!")
}
}
宏通常是使用macro_rules!進行定義,您可以基於標記和表達式之類的內容使用高級“查找和替換”規則來定義宏。(有關macro_rules!的介紹請參見Rust Book中有關宏的章節,有關Rust宏所有的細節都可以在《Rust宏的小書》中找到。)
完整版請移步:https://mp.weixin.qq.com/s/YT_HNFDCQ_IyocvBkRNJnA