簡體   English   中英

如何創建類似函數的過程宏?

[英]How do I create a function-like procedural macro?

應該如何定義a_proc_macro以便它“返回”一個 5?

fn main() {
    let a = a_proc_macro!();
    assert!(a == 5);
}

閱讀Rust 編程語言關於的章節說:

類函數宏定義看起來像 function 調用的宏。 與宏規則類似macro_rules! 宏,它們比函數更靈活; 例如,他們可以取未知數量的 arguments。 但是, macro_rules! 只能使用我們在“使用macro_rules! 用於通用元編程”之前。 類似函數的宏采用TokenStream參數,它們的定義使用 Rust 代碼操縱TokenStream ,就像其他兩種類型的過程宏一樣。 類似函數的宏的一個例子是sql! 可以這樣調用的宏:

 let sql = sql;(SELECT * FROM posts WHERE id=1);

該宏將解析其中的 SQL 語句並檢查其語法是否正確,這比宏規則的處理要復雜得多macro_rules! 宏可以做。 sql! 宏將被定義如下:

 #[proc_macro] pub fn sql(input: TokenStream) -> TokenStream {

這個定義類似於自定義派生宏的簽名:我們接收括號內的標記並返回我們想要生成的代碼。


由於Rust 1.45 ,您可以調用類似函數的過程宏作為表達式。

example
├── Cargo.toml
├── example-macro
│   ├── Cargo.toml
│   ├── src
│   │   └── lib.rs
├── src
│   └── main.rs

貨運.toml

[package]
name = "example"
version = "0.1.0"
edition = "2018"

[dependencies]
example-macro = { path = "example-macro" }

src/main.rs

fn main() {
    assert_eq!(example_macro::a_proc_macro!(), 5);
}

示例宏/Cargo.toml

[package]
name = "example-macro"
version = "0.1.0"
edition = "2018"

[lib]
proc-macro = true

示例宏/src/lib.rs

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro]
pub fn a_proc_macro(_input: TokenStream) -> TokenStream {
    "5".parse().unwrap()
}

也可以看看:

在穩定的 Rust 中直接定義類似表達式的過程宏是不可能的。 如果您可以每晚使用, Shepmaster 的回答顯示了如何使用。

如果您處於穩定狀態,您仍然可以模擬類似表達式的過程宏,如下所示:

  • 定義一個擴展為 function 的過程宏,其計算結果為您要調用的表達式;
  • 然后定義一個常規宏,該宏擴展為嵌入 function 定義和調用的塊。

在您的情況下,您將像這樣定義程序宏:

#[proc_macro]
pub fn a_proc_macro_impl(_input: TokenStream) -> TokenStream {
    "fn output() -> usize { 5 }".parse().unwrap()
}

...輔助macro_rules! 宏遵循這種模式:

macro_rules! a_proc_macro {
    ($($t:tt)*) => {{
        struct _X;
        impl _X {
            a_proc_macro!($($t)*);
        }
        _X::output()
    }}
}

這是一個 hack,而且很麻煩,但是proc-macro-hack crate 來拯救它,它可以更容易地使用上述技術生成過程宏。 proc-macro-hack crate 的幫助下,您可以運行 Shepmaster 在 stable 上的回答中幾乎未更改的代碼:

  • 編輯Cargo.toml文件並將proc-macro-hack = "0.5.11"添加到依賴項部分;
  • 添加#[proc_macro_hack] use example_macro::a_proc_macro; src/main.rs中,調用a_proc_macro! 從本地命名空間。
  • example-macro/src/lib.rsa_proc_macro的定義之前添加#[proc_macro_hack::proc_macro_hack]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM