多语种网站营销,网站管理设置,微信社区官网,wordpress技术博客模板有没有同学记得我们一起挖了多少个坑#xff1f;嗯…其实我自己也不记得了#xff0c;今天我们再来挖一个特殊的坑#xff0c;这个坑可以说是挖到根源了——元编程。元编程是编程领域的一个重要概念#xff0c;它允许程序将代码作为数据#xff0c;在运行时对代码进行修改…有没有同学记得我们一起挖了多少个坑嗯…其实我自己也不记得了今天我们再来挖一个特殊的坑这个坑可以说是挖到根源了——元编程。元编程是编程领域的一个重要概念它允许程序将代码作为数据在运行时对代码进行修改或替换。如果你熟悉Java此时是不是想到了Java的反射机制没错它就是属于元编程的一种。反射Rust也同样支持反射Rust的反射是由标准库中的std::any::Any包支持的。这个包中提供了以下几个方法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.4quote 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 manipulatelet ast syn::parse(input).unwrap();// Build the trait implementationimpl_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()}这里使用了两个cratesyn和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();}运行结果显示我们能够成功在实现中捕获到结构体的名字。总结我们在本文中先后介绍了Rust的两种元编程反射和宏。其中反射提供的功能能力较弱但是宏提供的功能非常强大。我们所介绍的宏的相关知识其实只是皮毛要想真正理解宏还需要花更多的时间学习。https://juejin.im/post/5e8f2f8b518825738e21725e