欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報(bào)激活碼778899分享:2311rust過程宏的示例

柚子快報(bào)激活碼778899分享:2311rust過程宏的示例

http://yzkb.51969.com/

原文

Rust2018中的過程宏

在Rust2018版本中,我最喜歡的功能是過程宏.在Rust中,過程宏有著悠久而傳奇的歷史(并繼續(xù)擁有傳奇的未來!) 因?yàn)?018年版極大改善了定義和使用它們的體驗(yàn).

什么是過程宏

過程宏是,在編譯時(shí)用一段語法,生成新語法的函數(shù).Rust2018中的過程宏有三個(gè)風(fēng)格:

1,自Rust1.15以來,#[derive]模式宏一直很穩(wěn)定,并把#[derive(Debug)]的所有優(yōu)點(diǎn)和易用性也帶到了用戶定義的特征中,如Serde的#[derive(Deserialize)]. 2,函數(shù)式宏,在2018版中是新的穩(wěn)定版本,并允許在基于crates.io的庫中定義:

env!("FOO")

format_args!("...")

宏.類似macro_rules!宏.

3,我最喜歡的屬性宏,也是2018版中的新功能,它允許在Rust函數(shù)上提供輕量注解,來編譯時(shí)語法轉(zhuǎn)換代碼.

可在清單中用proc-macro=true指定宏.使用時(shí),Rust編譯器會(huì)加載過程宏,并在展開調(diào)用時(shí)執(zhí)行它. 即Cargo可控制過程宏的版本,且可像其他Cargo依賴項(xiàng)一樣輕松使用它們!

定義過程宏

這三類的定義方式略微不同,在此以屬性宏為例.首先,標(biāo)記Cargo.toml:

[lib]

proc-macro = true

然后在src/lib.rs中,可編寫宏:

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_attribute]

pub fn hello(attr: TokenStream, item: TokenStream) -> TokenStream {

//...

}

然后可在tests/smoke.rs中編寫單元測(cè)試:

#[my_crate::hello]

fn wrapped_function() {}

#[test]

fn works() {

wrapped_function();

}

…就這樣!執(zhí)行cargo test的測(cè)試時(shí),Cargo編譯過程宏.之后,它編譯編譯時(shí)加載宏的單元測(cè)試,執(zhí)行hello函數(shù)并編譯生成的語法.

可見過程宏的幾個(gè)重要屬性:

1,輸入/輸出是TokenStream類型 2,編譯時(shí)可執(zhí)行任意代碼,即幾乎不受限! 3,過程宏與模塊系統(tǒng)整合,即可像其他名字一樣導(dǎo)入.

先深入了解其中的一些要點(diǎn).

宏和模塊系統(tǒng)

宏現(xiàn)在與Rust中的模塊系統(tǒng)整合.表明導(dǎo)入宏時(shí)不再需要笨拙的#[macro_use]屬性!不是:

#[macro_use]

extern crate log;

fn main() {

debug!("hello, ");

info!("world!");

}

你可以如下:

use log::info;

fn main() {

log::debug!("hello, ");

info!("world!");

}

好處不僅限于!風(fēng)格的macro_rules宏,因?yàn)楝F(xiàn)在可轉(zhuǎn)換如下代碼:

#[macro_use]

extern crate serde_derive;

#[derive(Deserialize)]

struct Foo {

//...

}

//為

use serde::Deserialize;

#[derive(Deserialize)]

struct Foo {

//...

}

甚至不需要顯式依賴Cargo.toml中的serde_derive!,只需要:

[dependencies]

serde = { version = '1.0.82', features = ['derive'] }

TokenStream內(nèi)部

神秘的TokenStream類型,來自編譯器提供的proc_macro倉庫. 首次添加TokenStream時(shí),只能調(diào)用to_string()或parse()來回來轉(zhuǎn)換其為串或從串轉(zhuǎn)換. 從Rust2018開始,可直接操作TokenStream中的令牌.

TokenStream"只是"TokenTree上的一個(gè)迭代器.Rust中的所有語法都分四類,即TokenTree的四種變體: 1,Ident是如foo或bar的標(biāo)識(shí).它還包含如self和super的關(guān)鍵字. 2,字面(Literal)包括像1,"foo"和"b"等內(nèi)容.所有字面都是表示程序中常量值的一個(gè)令牌. 3,Punct表示標(biāo)點(diǎn)符號(hào),而不是分隔符.

如.是foo.bar字段訪問中的Punct令牌.像=>此多符標(biāo)點(diǎn)符號(hào)表示為兩個(gè)Punct標(biāo)記,一個(gè)表示=,一個(gè)表示>,Spacing枚舉表示=與>相鄰.

4,Group是"樹"項(xiàng)最相關(guān)的地方,因?yàn)镚roup代表一個(gè)分隔的子令牌流.如,(a,b)是以括號(hào)作為分隔符的Group,內(nèi)部令牌流是a,b.

最小化TokenTree對(duì)穩(wěn)定性至關(guān)重要. 穩(wěn)定Rust的AST是不可行的,因?yàn)槟潜硎静荒芨淖兯?(想像假如如果不能添加?符號(hào)).

用TokenStream與過程宏通信,在同時(shí)可編譯和處理較舊過程宏時(shí),編譯器可添加新的語言語法.不過,先看看如何從TokenStream中取有用的信息.

解析TokenStream

但,只需要看看syn倉庫. 使用syn倉庫,可用單行代碼解析RustAST:

#[proc_macro_attribute]

pub fn hello(attr: TokenStream, item: TokenStream) -> TokenStream {

let input = syn::parse_macro_input!(item as syn::ItemFn);

let name = &input.ident;

let abi = &input.abi;

//...

}

syn倉庫不僅可解析內(nèi)置語法,且還可輕松地為自己的語法編寫遞歸下降解析器.更多.

生成TokenStream

不僅要以TokenStream作為過程宏的輸入,還要生成TokenStream作為輸出.一般要求輸出是有效的Rust語法,但與輸入一樣,它只是要構(gòu)建的令牌列表. 創(chuàng)建TokenStream的唯一方法是通過其FromIterator實(shí)現(xiàn),即必須逐個(gè)創(chuàng)建每個(gè)令牌并聚集它到TokenStream中. 不過,這很乏味,所以看看syn的quote兄弟倉庫. quote倉庫是Rust的準(zhǔn)引用實(shí)現(xiàn),主要提供了一個(gè)方便的宏:

use quote::quote;

#[proc_macro_attribute]

pub fn hello(attr: TokenStream, item: TokenStream) -> TokenStream {

let input = syn::parse_macro_input!(item as syn::ItemFn);

let name = &input.ident;

//輸入函數(shù)總是等價(jià)于返回`42`,對(duì)不?

let result = quote! {

fn #name() -> u32 { 42 }

};

result.into()

}

quote!宏這里允許你編寫大部分Rust語法,并用#foo從環(huán)境中快速插值變量.

令牌和跨度(Span)

也許Rust2018中過程宏的最大特性是可自定義和使用每個(gè)令牌上的Span信息,這樣可從過程宏中取得驚人的語法錯(cuò)誤消息:

error: expected `fn`

--> src/main.rs:3:14

|

3 | my_annotate!(not_fn foo() {});

| ^^^^^^

及完全自定義的錯(cuò)誤消息:

錯(cuò)誤:`導(dǎo)入`方法必須至少`有一個(gè)`參數(shù)

--> invalid-imports.rs:12:5

|

12 | fn f1();

| ^^^^^^^^

Span可看作是原始源文件的指針,一般表示,foo,"Ident令牌來自文件bar.rs,第4行第5列,長(zhǎng)度為3個(gè)字節(jié)". 此信息主要由包含警告和錯(cuò)誤消息的編譯器診斷使用.

在Rust2018中,每個(gè)TokenTree都有個(gè)與之關(guān)聯(lián)的Span.即,如果把所有輸入令牌的Span保留到輸出中,則即使生成全新語法,編譯器的錯(cuò)誤消息仍是準(zhǔn)確的! 如,如下一個(gè)小宏:

#[proc_macro]

pub fn make_pub(item: TokenStream) -> TokenStream {

let result = quote! {

pub #item

};

result.into()

}

按如下調(diào)用:

my_macro::make_pub! {

static X: u32 = "foo";

}

是無效的,因?yàn)閺膽?yīng)該返回u32的函數(shù)返回一個(gè)串,編譯器幫助診斷問題為:

`error[E0308]`:`類型`不匹配

--> src/main.rs:1:37

|

1 | my_macro::make_pub!(static X: u32 = "foo");

| ^^^^^ expected u32, found reference

|

=注意:期望類型為`"U32"`

找到類型`'&'staticstr'`

錯(cuò)誤:因?yàn)樯弦粋€(gè)錯(cuò)誤而中止

在此可見,盡管正在生成全新語法,但編譯器可保留span信息,以繼續(xù)為編寫代碼提供針對(duì)性的診斷.

生態(tài)中的過程宏

syn,quote和proc-macro2是編寫過程宏的首選庫.方便自定義解析器,解析現(xiàn)有語法,創(chuàng)建新語法,使用舊版本的Rust等等!

Serde這里及Serialize和Deserialize的繼承宏可能是生態(tài)中最常用的宏.它們有令人印象深刻的配置量,是小注解但強(qiáng)大的很好示例.

wasm-bindgen項(xiàng)目在Rust中,使用屬性宏輕松定義接口,并從JS導(dǎo)入接口. #[wasm_bindgen]輕量注解方便理解傳入和傳出內(nèi)容,并刪除了大量轉(zhuǎn)換樣板.

gobject_gen!宏是GNOME項(xiàng)目的實(shí)驗(yàn)性IDL,來在Rust中安全地定義GObject對(duì)象,避免手寫來與C語言通信,并用Rust寫其他GObject實(shí)例交互期望的所有膠水.

Rocket框架最近切換到了過程宏,并展示了過程宏的一些最新功能,如自定義診斷,自定義跨度創(chuàng)建等.

柚子快報(bào)激活碼778899分享:2311rust過程宏的示例

http://yzkb.51969.com/

相關(guān)文章

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/17825973.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄