python入坑指南_Rust入坑指南:萬物初始

有沒有同學記得我們一起挖了多少個坑?嗯…其實我自己也不記得了,今天我們再來挖一個特殊的坑,這個坑可以說是挖到根源了——元編程。

元編程是編程領域的一個重要概念,它允許程序將代碼作為數據,在運行時對代碼進行修改或替換。如果你熟悉Java,此時是不是想到了Java的反射機制?沒錯,它就是屬于元編程的一種。

反射

Rust也同樣支持反射,Rust的反射是由標準庫中的std::any::Any包支持的。

這個包中提供了以下幾個方法

wAAACwAAAAAAQABAEACAkQBADs=

TypeId是Rust中的一種類型,它被用來表示某個類型的唯一標識。type_id(&self)這個方法返回變量的TypeId。

is()方法則用來判斷某個函數的類型。

可以看一下它的源碼實現 pub fn is(&self) -> bool {

let t = TypeId::of::();

let concrete = self.type_id();

t == concrete

}

可以看到它的實現非常簡單,就是對比TypeId。

downcast_ref()和downcast_mut()是一對用于將泛型T轉換為具體類型的方法。其返回的類型是Option和Option,也就是說downcast_ref()將類型T轉換為不可變引用,而downcast_mut()將T轉換為可變引用。

最后我們通過一個例子來看一下這幾個函數的具體使用方法。use std::any::{Any, TypeId};

fn main() {

let v1 = "Jackey";

let mut a: &Any;

a = &v1;

println!("{:?}", a.type_id());

assert!(a.is::());

print_any(&v1);

let v2: u32 = 33;

print_any(&v2);

}

fn print_any(any: &Any) {

if let Some(v) = any.downcast_ref::() {

println!("u32 {:x}", v);

} else if let Some(v) = any.downcast_ref::() {

println!("str {:?}", v);

} else {

println!("else");

}

}

Rust的反射機制提供的功能比較有限,但是Rust還提供了宏來支持元編程。

到目前為止,宏對我們來說是一個既熟悉又陌生的概念,熟悉是因為我們一直在使用println!宏,陌生則是因為我們從沒有詳細介紹過它。

對于println!宏,我們直觀上的使用感受是它和函數差不多。但兩者之間還是有一定的區別的。

我們知道對于函數,它接收參數的個數是固定的,并且在函數定義時就已經固定了。而宏接收的參數個數則是不固定的。

這里我們說的宏都是類似函數的宏,此外,Rust還有一種宏是類似于屬性的宏。它有點類似于Java中的注解,通常作為一種標記寫在函數名上方。#[route(GET, "/")]

fn index() {

route在這里是用來指定接口方法的,對于這個服務來講,根路徑的GET請求都被路由到這個index函數上。這樣的宏是通過屬于過程宏,它的定義使用了#[proc_macro_attribute]注解。而函數類似的過程宏在定義時使用的注解是#[proc_macro]。

除了過程宏以外,宏的另一大分類叫做聲明宏。聲明宏是通過macro_rules!來聲明定義的宏,它比過程宏的應用要更加廣泛。我們曾經接觸過的vec!就是聲明宏的一種。它的定義如下:#[macro_export]

macro_rules! vec {

( $( $x:expr ),* ) => {

{

let mut temp_vec = Vec::new();

$(

temp_vec.push($x);

)*

temp_vec

}

};

}

下面我們來定義一個屬于自己的宏。

自定義宏需要使用derive注解。(例子來自the book)

我們先來創建一個叫做hello_macro的lib庫,只定義一個trait。pub trait HelloMacro {

fn hello_macro();

}

接著再創建一個子目錄hello_macro_derive,在hello_macro_derive/Cargo.toml文件中添加依賴[lib]

proc-macro = true

[dependencies]

syn = "0.14.4"

quote = "0.6.3"

然后就可以在hello_macro_derive/lib.rs文件中定義我們自定義宏的功能實現了。extern crate proc_macro;

use crate::proc_macro::TokenStream;

use quote::quote;

use syn;

#[proc_macro_derive(HelloMacro)]

pub fn hello_macro_derive(input: TokenStream) -> TokenStream {

// Construct a representation of Rust code as a syntax tree

// that we can manipulate

let ast = syn::parse(input).unwrap();

// Build the trait implementation

impl_hello_macro(&ast)

}

fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {

let name = &ast.ident;

let gen = quote! {

impl HelloMacro for #name {

fn hello_macro() {

println!("Hello, Macro! My name is {}", stringify!(#name));

}

}

};

gen.into()

}

這里使用了兩個crate:syn和quote,其中syn是把Rust代碼轉換成一種特殊的可操作的數據結構,而quote的作用則與它剛好相反。

可以看到,我們自定義宏使用的注解是#[proc_macro_derive(HelloMacro)],其中HelloMacro是宏的名稱,在使用時,我們只需要使用注解#[derive(HelloMacro)]即可。

在使用時我們應該先引入這兩個依賴hello_macro = { path = "../hello_macro" }

hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }

然后再來使用use hello_macro::HelloMacro;

use hello_macro_derive::HelloMacro;

#[derive(HelloMacro)]

struct Pancakes;

fn main() {

Pancakes::hello_macro();

}

運行結果顯示,我們能夠成功在實現中捕獲到結構體的名字。

wAAACwAAAAAAQABAEACAkQBADs=

總結

我們在本文中先后介紹了Rust的兩種元編程:反射和宏。其中反射提供的功能能力較弱,但是宏提供的功能非常強大。我們所介紹的宏的相關知識其實只是皮毛,要想真正理解宏,還需要花更多的時間學習。

https://juejin.im/post/5e8f2f8b518825738e21725e

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

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

相關文章

python和noip的區別_【noi與noip的區別】

什么是NOINOI:全國青少年信息學奧林匹克(NOI)是國內包括港澳在內的省級代表隊高水平的大賽,自1984年至今,在國內包括香港、澳門組織競賽活動。每年經各省選拔產生5名選手(其中一名是女選手),由中國計算機學會在計算機普及較好的城…

gradle和maven區別

原文連接:http://blog.csdn.net/jueane/article/details/50383431 --------------------------------------------- Gradle和Maven都是項目自動構建工具,編譯源代碼只是整個過程的一個方面,更重要的是,你要把你的軟件發布到生產…

iOS開發提問題

1、打造最受企業歡迎的iOS開發者: 一直都存在的問題,什么樣的員工最受企業歡迎?一直也有人在努力提升自己,成為受企業歡迎的員工然而,我們應該往方向去提升自己呢?88家知名企業今年來iOS面試題合集&#xf…

maven引用公共包_使用github作為maven倉庫存放發布自己的jar包依賴 實現多個項目公共部分代碼的集中,避免團隊中多個項目之間代碼的復制粘貼...

使用github作為maven倉庫存放發布自己的jar包依賴 實現多個項目公共部分代碼的集中,避免團隊中多個項目之間代碼的復制粘貼。1、首先在本地maven位置的配置文件setting.xml(沒有該文件就新建這個文件)中,添加配置maven倉庫的地址。我用的是我的GitHub倉庫…

Gradle筆記——Gradle的簡介與安裝

原文連接:http://blog.csdn.net/maosidiaoxian/article/details/40109337 gradle專欄 ----------------------------------------- Gradle 安裝 1,安裝JDK,并配置JAVA_HOME環境變量。因為Gradle是用Groovy編寫的,而Groovy基于JA…

WPF之鼠標滑動切換圖片

原文:WPF之鼠標滑動切換圖片在網上找了一會兒也沒找到我想要的效果,還是自己動手,豐衣足食吧。 需求:當前面板中只顯示一張圖片,圖片欄的下部有用來顯示當前圖片處于圖片隊列中的位置的圓球,并且點擊下部欄內的圓球可以…

CPU的核心數、線程數的關系和區別

原文地址:http://blog.csdn.net/yu132563/article/details/45222935 ------------------------------------- 我們在選購電腦的時候,CPU是一個需要考慮到核心因素,因為它決定了電腦的性能等級。CPU從早期的單核,發展到現在的雙核…

mysql in 子查詢優化_mysql in 子查詢 容易優化

mysql in 子查詢 簡單優化 大數量下,不要使用 in 嵌套子查詢,性能很差,很容易卡死。 ? 簡單調整方式如下: select uid,nick_name from uc_users where uid in(select fid from uc_follow where uid#uid#) ? 可拆解成&#xff1a…

谷歌瀏覽器插件入門示例

2019獨角獸企業重金招聘Python工程師標準>>> 實現:任何網址實現圖片下載和獲取當前域名的cookies的json字符串。 圖片下載是給小白用的,可以選中批量下載,獲取cookies 是為了方便程序員調試用。 獲取cookies: git地址:…

Fiddler中response亂碼的解決方案

原文連接:http://blog.csdn.net/quiet_girl/article/details/50577828 ---------------------------------------------------------- 有時候我們看到Response中的HTML是亂碼的, 這是因為HTML被壓縮了, 我們可以通過兩種方法去解壓縮。 解決…

線程帶來的風險

線程安全性問題 多線程環境下 多個線程共享一個資源對資源進行非原子性操作。 以上三者都存在就會發生線程安全性問題 如文中的賣火車票問題:http://blog.csdn.net/zengmingen/article/details/53217229 原因是:一行java代碼轉成.class字節碼文件后是…

vue內引入語音播報功能

為什么80%的碼農都做不了架構師?>>> 在vue項目中引入語音播報,使用的科大訊飛語音接入, 具體思路為每次接收到語音信息后存入一個數組,然后監聽這個數組,開始沖第一個索引播放,并且同時根據vue…

php mysql 排序規則_php 數組排序以及按照某個字段排序

如果你已經使用了一段時間PHP的話,那么,你應該已經對它的數組比較熟悉了——這種數據結構允許你在單個變量中存儲多個值,并且可以把它們作為一個集合進行操作。經常,開發人員發現在PHP中使用這種數據結構對值或者數組元素進行排序…

單例問題與線程安全

餓漢式 沒有線程安全性問題 懶漢式 public class SingletonDemo2 {private static SingletonDemo2 instance;private SingletonDemo2() {}public static SingletonDemo2 getInstance() {if(instancenull) {instancenew SingletonDemo2();}return instance;}}如果遇到多線程。上…

python 音速_中國大學MOOC的APP(慕課)2021用Python玩轉數據章節答案

在高技術戰爭件下,信息的獲取相當于人的感覺器官,信息的傳輸相當于人的神經網絡,信息的處理相當于人的大腦,( )則將它們聯系為一個整體,構成了作戰的神經系統。車身可拆卸的連接有螺紋連接、卡口鏈接、鉸鏈連接。在高技術戰爭件下,信息的獲取相當于人的感覺器官,信息的傳輸相當…

Mysql中的觸發器

原文地址:https://www.cnblogs.com/zyshi/p/6618839.html ---------------------------------------------------------什么是觸發器 簡單的說,就是一張表發生了某件事(插入、刪除、更新操作),然后自動觸發了預先編寫好…

一張圖理解JS的原型(prototype、_proto_、constructor的三角關系)

注意:前方高能預警,請認真仔細看完,閱讀完后自己再次畫下原型圖,相信你一定會有更深刻的認識。(推薦炒雞好用的畫流程圖的軟件ProcessOn)構造函數:function Foo ( ) { };實例對象:let f1new Foo;let o1new …

Oracle觸發器和MySQL觸發器之間的區別

原文鏈接:http://blog.csdn.net/a19881029/article/details/37820363 -----------------------------------------------------------Oracle觸發器格式:[plain] view plaincopyCREATE [OR REPLACE] TRIGGER trigger_name BEFORE|AFTER INSERT|UPDA…

下列選項中不符合python語言變量命名規則的是_學習Python第二日--基本概念和類型...

編程語言分類:解釋型語言和編譯型語言。解釋型語言不會產生額外的文件,運行時一行一行的翻譯。編譯型語言需要產生一個額外的文件,是電腦能夠識別的內容,運行后將產生額外的文件。 變量是可變的量,是它的值可以發生改變。變量的作用是保存值,保存的值可以是數據,而且保存…

HashMap死鎖原因及替代方案

原文鏈接:http://blog.csdn.net/fhzaitian/article/details/51505516 ------------------------------------------------------------------------1、首先我們需要簡單地了解一下HashMap數據結構 HashMap通常會用一個指針數組(假設為table[]&#xff09…