您的位置:首页 > 科技 > 能源 > 哪个网站有摄影作品_网络营销ppt课件_百度ai智能写作工具_网络优化培训要多少钱

哪个网站有摄影作品_网络营销ppt课件_百度ai智能写作工具_网络优化培训要多少钱

2024/12/25 20:39:56 来源:https://blog.csdn.net/neweastsun/article/details/144017995  浏览:    关键词:哪个网站有摄影作品_网络营销ppt课件_百度ai智能写作工具_网络优化培训要多少钱
哪个网站有摄影作品_网络营销ppt课件_百度ai智能写作工具_网络优化培训要多少钱

Rust中,属性宏(Attribute Macros)是一种强大的元编程工具。它们允许开发者通过自定义属性(以#[...]的形式)来扩展Rust语言的语法,从而在编译时对代码进行转换。属性宏在编译阶段起作用,能够读取和修改Rust抽象语法树(AST),以生成新的代码或者修改现有代码的行为。

本文带你从头自定义属性宏,用于自定义评估函数执行占用时间。
在这里插入图片描述

创建项目工程

首先创建主体项目 foo2, 然后进入该项目目录中,再创建macro_lib 项目,我们在子项目中实现属性宏代码。

# 创建主体工程
cargo new foo2 cd foo2
cargo new macro_lib --lib

项目树结构大致如下:

├── src
│   └── main.rs
├── macro_lib
│   ├── src
│   │   ├── log_duration.rs
│   │   └── lib.rs
│   ├── Cargo.toml
│   └── Cargo.lock
├── Cargo.toml
└── Cargo.lock

在主项目的cargo.toml中增加子项目依赖:

[dependencies]
macro_lib = { path = "./macro_lib" }

声明属性宏

我们在子项目的lib.rs中定义函数,并使用宏进行标识,告诉编译器该函数是宏声明:

// macro_lib/src/lib.rs#[proc_macro_attribute]
pub fn log_duration(args: TokenStream, item: TokenStream) -> TokenStream {log_duration_impl(args, item)
}

对于属性宏定义,函数名很重要,因为名称就是属性宏的名称。正如你所看到的,这需要两个不同的参数。第一个是传递给属性宏的参数,第二个是属性宏的目标。

为了实现于声明分离,我们定义新的文件实现log_duration_impl函数:

touch src/log_duration.rs

实现log_duration 属性宏

我将首先给你完整的实现,然后我将分解到目前为止我还没有使用的部分:

// macro_lib/src/log_duration.rsuse proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};pub(crate) fn log_duration_impl(_args: TokenStream, input: TokenStream) -> TokenStream {// 解析输入作为ItemFn类型,它是syn 提供的表示函数类型let input = parse_macro_input!(input as ItemFn);let ItemFn {// 函数签名sig,// 函数可见性标识vis,// 函数体block,// 其他属性attrs,} = input;// 抽取函数体语句let statements = block.stmts;// 存储函数名称标识符,用于日志记录let function_identifier = sig.ident.clone();// 使用解析输入重构函数,然后输出quote!(// 在该函数上重复其他所有属性(保持不变)#(#attrs)*// 重构函数声明#vis #sig {// 记录开始时间let __start = std::time::Instant::now();// 创建新的块,即函数的主体部分,存储返回值作为变量,后续可返回给父函数let __result = {#(#statements)*};// 记录函数执行时间println!("{} took {}μs", stringify!(#function_identifier), __start.elapsed().as_micros());// 返回结果return __result;}).into()
}

你之前可能没有看到的可能是:通过将输入解析为ItemFn而获得的签名和块字段。Sig包含函数的整个签名,而block包含函数的整个主体。这就是为什么,通过使用下面的代码,我们基本上可以重建未修改的函数:

// 在宏里面重建未修改fn#vis #sig #block

在本例中,你希望修改函数体,这就是为什么要创建封装原始函数块的新块。我们现在以及实现了属性宏,这里补充下lib.rs代码及依赖:

cargo.toml

[package]
name = "macro_lib"
version = "0.1.0"
edition = "2021"[lib]
name="macro_lib"
proc-macro = true
path = "src/lib.rs"[dependencies]
quote = "1.0.37"
syn = {version ="2.0.87", features=["full"] }

proc-macro = true 这个是标识该项目是过程宏项目。当然还需要引用 quote 和 syn

lib.rs完整代码

mod log_duration;extern crate proc_macro;use proc_macro::TokenStream;
use log_duration::log_duration_impl;#[proc_macro_attribute]
pub fn log_duration(args: TokenStream, item: TokenStream) -> TokenStream {log_duration_impl(args, item)
}

应该具体实现在log_duration文件中,因此需要声明mod,接着是引入log_duration_impl。下面我们看如何使用该宏。

使用属性宏

// main.rsuse macro_lib::log_duration;#[log_duration]
#[must_use]
fn function_to_benchmark() -> u16 {let mut counter = 0;for _ in 0..u16::MAX {counter += 1;}counter
}fn main() {println!("{}", function_to_benchmark());
}

输出结果:

function_to_benchmark took 498μs
65535

总结

本文完整实现了简单的属性宏,并采用声明与实现分离方式实现。如果你之前以及阅读本系列文章,应该不会感动很难懂。下面我们会继续更复杂的属性宏实现,来吧,一起学习rust!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com