rust詳解

前言

rust 學習曲線非常陡峭,但是基本語法也還算挺好理解,自動內存管理有點類似智能指針,基本看一下語法入門就可以大概理解,但是唯獨宏很難理解,語法非常晦澀。但是功能非常強大。聲明宏類似于c語言的宏處理,但是功能更強大。過程宏則類似于Android的注解編程,自定義AbstractProcessor,但是實現更優雅。
下面記錄一下宏處理的一些特點

正文

目前主流的文章都是翻譯自官方文檔,或者取部分Rust語言圣經,關鍵的部分特性就確實,只有rust宏詳解中非常詳細的介紹,這里簡要記錄一下特點

聲明宏

聲明宏主要是替代,主要是通過簡單的模式匹配,然后進行操作,這貌似非常容易處理面向對象的工廠模式,或者解決方法多參數操作,比如

macro_rules! vec {() => ($crate::__rust_force_expr!($crate::vec::Vec::new()));($elem:expr; $n:expr) => ($crate::__rust_force_expr!($crate::vec::from_elem($elem, $n)));($($x:expr),+ $(,)?) => ($crate::__rust_force_expr!(<[_]>::into_vec(// This rustc_box is not required, but it produces a dramatic improvement in compile// time when constructing arrays with many elements.#[rustc_box]$crate::boxed::Box::new([$($x),+]))));
}

這就是根據不同的匹配模式,=>的前半部分,替換成后半部。比如無參數的vec。因為這是系統接口,這里不在詳細介紹操作,只介紹匹配,

  1. ()是無參構造函數。
  2. ($elem:expr; $n:expr)這是匹配模式類似vec![1;5],這是創造一個size是5的,值是1的vec。
  3. 這個是匹配vec![1, 2, 3],這是構造一個內容是1、2、3的vec

第二個匹配模式中,$elem是為匹配的內容命名,方便后面使用,expr(一個表達式 (expression))指明匹配的元素,;就不用解釋,就是字面值。$n:expr同樣道理。
第二個匹配則稍微復雜一些,這里則用的是循環模式。循環是通過$(....)來指明的,括號內為循環內容,為了方便閱讀,則需要有分隔符和循環次數,這里是通過定義分隔符,+定義循環至少一次。$(,)?又是一個循環,循環內容則是。而循環一次則是最多一次。

所有的語句如下:

block:一個塊(比如一塊語句或者由大括號包圍的一個表達式)
expr:一個表達式 (expression)
ident:一個標識符 (identifier),包括關鍵字 (keywords)
item:一個條目(比如函數、結構體、模塊、impl 塊)
lifetime:一個生命周期注解(比如 'foo、'static)
literal:一個字面值(比如 “Hello World!”、3.14、‘🦀’)
meta:一個元信息(比如 #[…] 和 #![…] 屬性內部的東西)
pat:一個模式 (pattern)
path:一條路徑(比如 foo、::std::mem::replace、transmute::<_, int>)
stmt:一條語句 (statement)
tt:單棵標記樹
ty:一個類型
vis:一個可能為空的可視標識符(比如 pub、pub(in crate))

循環則如下:

反復捕獲的一般形式為 $ ( … ) sep rep。

$ 是字面上的美元符號標記
( … ) 是被反復匹配的模式,由小括號包圍。
sep 是可選的分隔標記。它不能是括號或者反復操作符 rep。常用例子有 , 和 ; 。
rep 是必須的重復操作符。當前可以是:

  1. ?:表示最多一次重復,所以此時不能前跟分隔標記。
  2. *:表示零次或多次重復。
  3. +:表示一次或多次重復。

過程宏

分為三類

  • 派生宏(Derive macro):用于結構體(struct)、枚舉(enum)、聯合(union)類型,可為其實現函數或特征(Trait)。
  • 屬性宏(Attribute macro):用在結構體、字段、函數等地方,為其指定屬性等功能。如標準庫中的#[inline]、#[derive(…)]等都是屬性宏。
  • 函數式宏(Function-like macro):用法與普通的規則宏類似,但功能更加強大,可實現任意語法樹層面的轉換功能。

聲明宏需要解析傳入的參數,進行匹配,而過程宏則需要自己解析傳入的內容,然后進行補充,生成代碼。這里需要解析TokenStream,舉個例子,就是用宏為一個結構體實現構建者模式。

#[derive(Builder)]
struct Command {// ...
}

最麻煩的是如何實現Builder

#[derive(Builder)]
struct Command {input_paht: String,// ...
}pub fn derive_builder(input: TokenStream) -> TokenStream {let input = parse_macro_input!(input as DeriveInput); // 解析input為 DeriveInput類型let input_ident = input.ident;  // 獲取原始類名let ident_builder = format_ident!("{}Builder", input_ident.to_string()); // 拼接builder類名if let Data::Struct(r) = input.data {   // 處理結構體let fields = r.fields;// 結構體屬性聲明let builder_fields = map_fields(&fields, &mut |(ident, ty)| {quote!(#ident: Option<#ty>,) });// 為builder增加set函數let builder_set_fields = map_fields(&fields, &mut |(ident, ty)| {quote!(pub fn #ident(mut self, value: #ty) -> Self {self.#ident = Some(value);self}) });// 獲取builder的屬性值let builder_lets = map_fields(&fields, &mut |(ident, _)| {quote!(let #ident = self.#ident.ok_or(format!("field {:?}  not set yet", stringify!(#ident),))?;)});// 初始化時的默認值let builder_fields_values = map_fields(&fields, &mut |(ident, _)| {quote!(#ident,)});quote!(impl #input_ident {pub fn builder() -> #ident_builder {#ident_builder::default()}}#[derive(Default)]pub struct #ident_builder {#builder_fields}impl #ident_builder {#builder_set_fieldspub fn build(self) -> Result<#input_ident, String> {#builder_letsOk(#input_ident{ #builder_fields_values })}}).into()} else {// 不支持非struct類型quote!().into()}
}fn map_fields<F>(fields: &Fields, mapper:&mut F) -> TokenStream2
whereF: FnMut((&Option<proc_macro2::Ident> ,  &Type)) -> TokenStream2,
{let fs = fields.iter().map(|field| mapper((&field.ident ,&field.ty)) );let stream2 = TokenStream2::from_iter(fs);stream2
}

這里為Command實現了builder方法如下:

impl Command{pub fn builder() -> CommandBuilder{CommandBuilder::default()}
}pub struct CommandBuilder{input_path: String,
}impl CommandBuilder{pub fn (mut self, value: String) -> Self {self.input_path = Some(value);self}pub fn build(self) -> Result<Command, String> {let input_path= self.input_path.ok_or(format!("field {:?}  not set yet", stringify!(input_path),))?;Ok(Command{ input_path })}}

屬性宏則可以傳入參數,讓控制更自由一些,這里就不在詳細介紹
函數式宏則相對比較簡單,類似聲明宏,但是可以不去匹配規則,更自由,功能更強大。

解析TokenStream需要依賴一些庫,這比較復雜,就不在詳細介紹。要結合自己代碼需求,慢慢理解。

分析工具
cargo.exe  install cargo-expandcargo.exe expand

后記

rust實在是復雜,這里解釋一些語法規則,以后遇到問題再補充。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210660.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210660.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210660.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【淘寶網消費類電子產品銷售數據可視化】

淘寶網消費類電子產品銷售數據可視化 引言數據爬取與處理數據可視化系統功能1. 總數據量分析2. 店鋪總數據3. 店鋪銷售額排名4. 不同電子商品銷售價格5. 單個商品價格排名6. 不同省份平均銷量7. 不同地區的平均銷售額8. 省份數量9. 每個省份有用的平均個數 創新點結語 引言 隨…

Linux 中 find 查找

目錄 1.普通查詢 2.按照文件大小查找 3.忽略文件字母大小寫查詢 4.根據修改時間查找 5. 取反 &#xff01; 6.根據用戶查詢 7.對查找出來的內容進行操作 1.普通查詢 find 路徑 -name "文件名" 如查看 etc 目錄下的passwd 的文件 find /etc -name "passwd&quo…

【周報2023.12.09】

周報2023.12.09 本周開展工作下周工作計劃 本周開展工作 本周開展的工作的話一共是一下幾點&#xff1a; 這三點的話是緊密相連的 邏輯這邊需要考慮的東西很多 點擊生成照片&#xff0c;然后獲取生成照片的狀態點擊生成照片&#xff0c;然后獲取生成照片的時間&#xff0c;并…

kettle完成mysql表與表之間的更新和插入

版本&#xff1a;20231209 kettle完成數據庫表與表之間的轉換非常的簡單&#xff0c;只需要在輸入模塊選擇&#xff1a;輸入表&#xff1b;在輸出模塊選擇&#xff1a;插入和更新表模塊 實例展示&#xff1a;將表stu1的數據同步到stu2&#xff0c;并覆蓋掉stu2原本的數據。 cr…

嵌入式學習---ARM時鐘體系

目錄 時鐘相關概念時鐘脈沖時鐘頻率時鐘的作用時鐘信號的生成 S3C2440的時鐘體系主時鐘晶振兩個PLL 時鐘啟動流程相關的寄存器 時鐘相關概念 時鐘脈沖 按一定電壓幅度&#xff0c;一定時間間隔連續發出的脈沖信號。它是一個周期性的信號&#xff0c;每個周期內包含一個上升沿…

ConvNeXt V2: Co-designing and Scaling ConvNets with Masked Autoencoders

1.關于稀疏卷積的解釋&#xff1a;https://zhuanlan.zhihu.com/p/382365889 2. 答案&#xff1a; 在深度學習領域&#xff0c;尤其是計算機視覺任務中&#xff0c;遮蔽圖像建模&#xff08;Masked Image Modeling, MIM&#xff09;是一種自監督學習策略&#xff0c;其基本思想…

向日葵遠程控制鼠標異常的問題

? 在通過向日葵進行遠程控制的時候&#xff0c;可能會遇到鼠標位置異常的問題。此時&#xff0c;不管怎么移動鼠標&#xff0c;都會停留在屏幕最上方&#xff0c;而無法點擊到正確的位置。如圖&#xff1a; 此時&#xff0c;如果啟用了“被控端鼠標”功能&#xff0c;可以正…

【Docker】swarm stack部署多service應用

前面我們已經學習過了Docker Compose&#xff0c;它可以用來進行一個完整的應用程序相互依賴的多個容器的編排的&#xff0c;但是缺點是只能在單機模式使用&#xff0c;不能在分布式多機器上使用&#xff1b;前面我們也學習了Docker swarm&#xff0c;它可以將單個服務部署為多…

基于EIoT能源物聯網的智能照明系統應用改造-安科瑞 蔣靜

【摘要】&#xff1a;隨著物聯網技術的發展&#xff0c;許多場所針對照明合理應用物聯網照明系統&#xff0c;照明作為工廠的重要能耗之一&#xff0c;工廠的照明智能化控制&#xff0c;如何優化控制、提高能源的利用率&#xff0c;達到節約能源的目的。將互聯網的技術應用到工…

【PHP】學習筆記一:數組及JSON

目錄 一、初始化創建數組&#xff1a; 1. 簡單數組&#xff1a; 2. 索引號是字符串數組&#xff08;對象數組&#xff09;&#xff1a; 3. 數組中增加一個元素&#xff1a; 4. 對象數組轉JSON字符串 5. JSON字符串轉數組 一、初始化創建數組&#xff1a; 1. 簡單數組&am…

golang的文件操作

獲取文件列表路徑 package _caseimport ("fmt""log""os""strings" )// 獲取文件路徑 // 源文件目錄 const sourceDir "file/"// 目標文件目錄 const destDir "det_file/"// 拿到目錄下完整的路徑 func geFiles…

Python數據科學視頻講解:數據挖掘與建模的注意事項

1.7 數據挖掘與建模的注意事項 視頻為《Python數據科學應用從入門到精通》張甜 楊維忠 清華大學出版社一書的隨書贈送視頻講解1.7節內容。本書已正式出版上市&#xff0c;當當、京東、淘寶等平臺熱銷中&#xff0c;搜索書名即可。內容涵蓋數據科學應用的全流程&#xff0c;包括…

sensitive word 敏感詞(臟詞) 如何忽略無意義的字符?達到更好的過濾效果?

忽略字符 說明 我們的敏感詞一般都是比較連續的&#xff0c;比如 傻帽 那就有大聰明發現&#xff0c;可以在中間加一些字符&#xff0c;比如【傻!#$帽】跳過檢測&#xff0c;但是罵人等攻擊力不減。 那么&#xff0c;如何應對這些類似的場景呢&#xff1f; 我們可以指定特…

CSS3技巧36:讓內容垂直居中的三種方式

讓內容垂直居中&#xff0c;是一個很重要的應用情景&#xff0c;在很多場合都會需要。這也是面試的時候&#xff0c;一些考官喜歡拿來初面的小題目。 這里&#xff0c;小結下讓內容垂直居中的三種方式。 當然&#xff0c;讀者如果有更好的方法&#xff0c;也可以提出來。 基本…

基于ssm技術的車庫智能管理平臺論文

摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術&#xff0c;讓傳統數據信息的管理升級為軟件存儲&#xff0c;歸納&#xff0c;集中處理數據信息的管理方式。本車庫智能管理平臺就是在這樣的大環境下誕生&#xff0c;其可以幫助管理者在短時間內處理完畢龐大的數據信息…

【自定義Source、Sink】Flink自定義Source、Sink對redis進行讀寫操作

使用ParameterTool讀取配置文件 Flink讀取參數的對象 Commons-cli&#xff1a; Apache提供的&#xff0c;需要引入依賴ParameterTool&#xff1a;Flink內置 ParameterTool 比 Commons-cli 使用上簡便&#xff1b; ParameterTool能避免Jar包的依賴沖突 建議使用第二種 使用Par…

西工大網絡空間安全學院計算機網絡實驗五——ACL配置

實驗五、ACL配置 一. 實驗目的 1. 掌握ACL的基本配置方法 二. 實驗內容 1. 基于如下圖所示的拓撲圖&#xff0c;對路由器進行正確的RIP協議配置&#xff1b; ? 首先引入3臺2811 IOS15型號的路由器、3臺2950-T24型號的交換機、4臺PC-PT型號的PC機、兩臺Server-PT型號的服務…

kafka學習筆記--生產者消息發送及原理

本文內容來自尚硅谷B站公開教學視頻&#xff0c;僅做個人總結、學習、復習使用&#xff0c;任何對此文章的引用&#xff0c;應當說明源出處為尚硅谷&#xff0c;不得用于商業用途。 如有侵權、聯系速刪 視頻教程鏈接&#xff1a;【尚硅谷】Kafka3.x教程&#xff08;從入門到調優…

JavaScript 的節流與防抖

// 函數防抖&#xff1a; 在事件被觸發 n 秒后再執行回調&#xff0c;如果在這 n 秒內事件又被觸發&#xff0c;則重新計時。// 函數節流&#xff1a; 規定一個單位時間&#xff0c;在這個單位時間內&#xff0c;只能有一次觸發事件的回調函數執行&#xff0c;如果在同一個單位…

Redis各種數據結構應用場景

Redis各種數據結構應用場景 一、基本類型 Redis的基本數據類型時&#xff0c;以下是它們的實際場景示例&#xff1a; 字符串&#xff08;String&#xff09;&#xff1a; 實際場景 緩存數據&#xff1a;將頻繁訪問的數據緩存在Redis中&#xff0c;以提高讀取速度。會話管理&…