Metavariables

官方文档确实写得很好,但是缺少一些风味,容易催眠‍

还是直接看例子更爽一些,通常我们可以从示例代码中之间看出官方文档要表达的意思,而且很多时候我们可以直接在示例代码的基础上改一改,就能满足我们自己的定制化需求。越抽象的东西,越是如此


item

An item is a component of a crate. Items are organized within a crate by a nested set of modules. Every crate has a single "outermost" anonymous module; all further items within the crate have paths within the module tree of the crate.

There are several kinds of items:

  • modules
  • extern crate declarations
  • use declarations
  • function definitions
  • type definitions
  • struct definitions
  • enumeration definitions
  • union definitions
  • constant items
  • static items
  • trait definitions
  • implementations
  • extern blocks

可以把整个 crate 比作一个 struct,这个 struct 里面的每一个 field 都是一个 item

这些 item 包括每一个 struct, fn, mod 的定义...

macro_rules! test_item {
($x: item) => {
// #[derive(Debug)]
$x
}
} test_item!(#[derive(Debug)] struct A{a: i32});
test_item!(fn foo(){println!("foo");});
test_item!(mod ma{}); let a = A{ a: 9};
println!("a: {:?}", a); // 输出 a: A { a: 9 } foo(); // 输出 foo

block

block 是匿名的命名空间作用域(anonymous namespace scope),就是以 { 开始 以 } 结束的整个块

macro_rules! test_block {
($x: block) => {
$x
}
} test_block!({
println!("block");
});

stmt

A statement is a component of a block, which is in turn a component of an outer expression or function

一个 stmt 可以是一个前面的 [item](## item), 或是 let statement, 或是 expression statement, 或是宏调用

macro_rules! test_stmt {
($x: stmt) => {
$x
}
} // let statement
test_stmt!(let state = 8);
println!("state: {}", state); // item
test_stmt!(#[derive(Debug)] struct B{b: i32}); // expression statement
test_stmt!{
if true {
1
} else {
2
}
}; // Macro Invocation
test_stmt!{
println!("Macro Invocation")
};

pat_param

用来 pattern match 的 param, 匹配一个 pattern, 像 match 内 => 左边的那些东西

pat_param 默认不匹配 or-pattern: 0 | 1 | 2

macro_rules! test_pat_param {
($x: pat_param) => {
$x
}
} struct Person {
car: Option<String>,
age: u8,
name: String,
gender: u8,
gfs: [String; 3],
} let person = Person {
car: Some("bmw".into()),
age: 18,
name: "hansomeboy".into(),
gender: 1,
gfs: ["Lisa".into(), "Jennie".into(), "Rosé".into()],
}; if let test_pat_param!(
Person {
car: Some(_),
age: person_age @ 13..=19,
name: ref person_name,
gfs: ref whole @ [.., ref last],
..
}
) = person {
println!("{} has a car and is {} years old, and his last GF is {}.", person_name, person_age, last);
} macro_rules! test_or_pattern {
($($x: pat_param)*) => ();
} test_or_pattern!{
Some(_)
Foo{x}
// error: no rules expected the token `|`
// 0 | 1 | 2
}

输出: hansomeboy has a car and is 18 years old, and his last GF is Rosé.

pat

用来匹配任意类型的 pattern, 包括 or-pattern: 0 | 1 | 2

macro_rules! test_pat {
($($pat:pat)*) => ();
} test_pat! {
"literal"
_
0..5
ref mut PatternsAreNice
0 | 1 | 2 | 3
}

expr

一个表达式 Expression

macro_rules! test_expr {
($($x: expr)*) => ();
} test_expr!{
"hello" // LiteralExpression
42 // LiteralExpression
a::b::c // PathExpression
a * b + c // OperatorExpression
&a
*a
-a
a = b
a += b
a || b && c
a & b | c
(a+b) - c
["a"] // ArrayExpression
a[b][c] // IndexExpression
("world", 42) // TupleExpression
tuple.0 // TupleIndexingExpression
Point {x: 1.0, y: 2.0} // StructExpression
foo() // CallExpression
"3.14".parse() // MethodCallExpression
foo().await // AwaitExpression
bar.await
hello.world // FieldExpression
move|x,y| -> () {} // ClosureExpression
async move {} // AsyncBlockExpression
0..10 // RangeExpression
(_, a) // UnderscoreExpression
vec![1,2,3] // MacroInvocation
continue 'hello // ContinueExpression
break 'hello // BreakExpression
return 42 // ReturnExpression
{} // BlockExpression
#[cfg("hello")]{}
unsafe {} // UnsafeExpression
if condition {} // IfExpression
if let a=b {} // IfLetExpression
match x {} // MatchExpression
}

ty

一个类型 Type

macro_rules! test_ty {
($($x: ty)*) => ();
} test_ty! {
u32
bool
char
str
String
[u8; 128]
(u32, bool)
&[u8]
Hello // User-defined types
fn(u8, u8) -> ()
&mut reference
*mut pointer
*const pointer
dyn Trait // Trait Object
impl Trait // Impl Trait
}

ident

一个标识符(用来标识变量、函数、类、对象或其他程序实体的名称) an IDENTIFIER_OR_KEYWORD or RAW_IDENTIFIER

macro_rules! test_ident {
($($x: ident)*) => ();
} test_ident! {
foo
_identifier
r#true // raw identifier
深圳
}

path

macro_rules! test_path {
($($x: path)*) => ();
} test_path! {
a::b::c
self::a::<b>::c
::std::time::Instant::now()
}

tt

标记树(token tree) 是一种介于标记 (token) 与 AST(abstract syntax tree) 之间的东西

几乎所有的 token 都是 token tree 的叶子节点(leaf node), 只有被 (...), [...]{...} 包裹在一起的一组一组的 tokens 不是叶子节点

a + b + (c + d[0]) + e

会被解析成下面的 token tree:

«a» «+» «b» «+» «(   )» «+» «e»
╭────────┴──────────╮
«c» «+» «d» «[ ]»
╭─┴─╮
«0»

可以看出 token tree 的 root 节点其实是第一行的这一整组 token: «a» «+» «b» «+» «( )» «+» «e», 而不是单一的 node

而 AST 会生成下面这种只有一个 root 节点的数状结构:

              ┌─────────┐
│ BinOp │
│ op: Add │
┌╴│ lhs: ◌ │
┌─────────┐ │ │ rhs: ◌ │╶┐ ┌─────────┐
│ Var │╶┘ └─────────┘ └╴│ BinOp │
│ name: a │ │ op: Add │
└─────────┘ ┌╴│ lhs: ◌ │
┌─────────┐ │ │ rhs: ◌ │╶┐ ┌─────────┐
│ Var │╶┘ └─────────┘ └╴│ BinOp │
│ name: b │ │ op: Add │
└─────────┘ ┌╴│ lhs: ◌ │
┌─────────┐ │ │ rhs: ◌ │╶┐ ┌─────────┐
│ BinOp │╶┘ └─────────┘ └╴│ Var │
│ op: Add │ │ name: e │
┌╴│ lhs: ◌ │ └─────────┘
┌─────────┐ │ │ rhs: ◌ │╶┐ ┌─────────┐
│ Var │╶┘ └─────────┘ └╴│ Index │
│ name: c │ ┌╴│ arr: ◌ │
└─────────┘ ┌─────────┐ │ │ ind: ◌ │╶┐ ┌─────────┐
│ Var │╶┘ └─────────┘ └╴│ LitInt │
│ name: d │ │ val: 0 │
└─────────┘ └─────────┘
macro_rules! test_tt {
($($x: tt)*) => {
println!("test_tt:");
$( println!("{:?}", stringify!($x)); )*
}
} test_tt! {
(a + b + (c + d[0]) + e)
[a + b + (c + d[0]) + e]
{a + b + (c + d[0]) + e}
}
test_tt! {
a + b + (c + d[2]) + e
}

输出:

test_tt:
"(a + b + (c + d [0]) + e)"
"[a + b + (c + d [0]) + e]"
"{ a + b + (c + d [0]) + e }"
test_tt:
"a"
"+"
"b"
"+"
"(c + d [2])"
"+"
"e"

meta

用来匹配 attribute 属性

就是那些写在 struct/enum/fn 前面的 #[...] #![...]

macro_rules! test_meta {
($(#$(!)?[$meta: meta])*) => ();
} test_meta! {
#[hello]
#![world]
#[a="b"]
}

lifetime

macro_rules! test_lifetime {
($($x: lifetime)*) => ();
} test_lifetime! {
'a
'_
'static
}

vis

visibility-and-privacy

macro_rules! test_vis {
// ∨~~Note this comma, since we cannot repeat a `vis` fragment on its own
($($x: vis,)*) => ();
} test_vis! {
,
pub,
pub(crate),
pub(super),
pub(self),
pub(in crate::a::b),
}

literal

macro_rules! test_literal {
($($x: literal)*) => ();
} test_literal! {
0
b'x'
'x'
"hello"
true
}

Rust 声明式宏中的 Metavariables 有哪些的更多相关文章

  1. Spring -12 -声明式事务及完整的XML配置文件信息 -声明式事务中的相关属性(tx:advice的标签)

    1.编程式事务: 1.1由程序员编程事务控制代码. 1.2OpenSessionInView 就属于编程式事务: session.commit()和rollback() 2.声明式事务: 2.1事务控 ...

  2. Jenkins 在声明式 pipeline 中并行执行任务

    在持续集成的过程中,并行的执行那些没有依赖关系的任务可以缩短整个执行过程.Jenkins 的 pipeline 功能支持我们用代码来配置持续集成的过程.本文将介绍在 Jenkins 中使用声明式 pi ...

  3. mysql事务管理及spring声明式事务中主动异常抛出使数据库回滚

    mysql的引擎常用的有两个,一个MyISAM,另一个是InnoDB,mysql默认的为MyISAM,而InnoDB才是支持事务的.所以一般需要修改下,如何修改就不说了. 事务需要依赖数据库,好久没使 ...

  4. spring 声明式事务中try catch捕获异常

    原文:http://heroliuxun.iteye.com/blog/848122 今天遇到了一个这个问题 最近遇到这样的问题,使用spring时,在业务层需要捕获异常(特殊需要),当前一般情况下不 ...

  5. Spring声明式事务不回滚问题

    疑问,确实像往常一样在service上添加了注解 @Transactional,为什么查询数据库时还是发现有数据不一致的情况,想想肯定是事务没起作用,出现异常的时候数据没有回滚.于是就对相关代码进行了 ...

  6. Jenkins pipeline声明式语法

    目录 一.最简结构 二.简单例子 一.最简结构 pipeline {     agent any     stages {         stage('pull') {             st ...

  7. Spring中的事物管理,用 @Transactional 注解声明式地管理事务

    事物: 事务管理是企业级应用程序开发中必不可少的技术,  用来确保数据的 完整性和 一致性. 事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用 事务的四 ...

  8. C#中手工进行声明式验证,从此远离if验证

    今天在一个ASP.NET MVC Controller Action中写代码时,需要对ViewModel的字段进行验证.但这个Action处理的是手工编写的ajax请求(不是表单提交),无法使用ASP ...

  9. 声明式RESTful客户端在asp.net core中的应用

    1 声明式RESTful客户端 声明式服务调用的客户端,常见有安卓的Retrofit.SpringCloud的Feign等,.net有Refit和WebApiClient,这些客户端都是以java或. ...

  10. vue中声明式导航和编程式导航

    官方文档:https://router.vuejs.org/zh-cn/essentials/navigation.html 声明式导航和编程式导航 共同点: 都能进行导航,都可以触发路由,实现组件切 ...

随机推荐

  1. 团队如何选择合适的Git分支策略?

    现代软件开发过程中要实现高效的团队协作,需要使用代码分支管理工具实现代码的共享.追溯.回滚及维护等功能.目前流行的代码管理工具,包括CVS,SVN,Git,Mercurial等. 相比CVS和SVN的 ...

  2. python入门教程之八列表,字典,字符串,集合常用操作

    一列表常用方法 Python包含以下函数: 序号 函数 1 cmp(list1, list2)比较两个列表的元素 2 len(list)列表元素个数 3 max(list)返回列表元素最大值 4 mi ...

  3. python模拟鼠标键盘操作

    前言 1 懒人,工作中可以模拟真人操作,不用自己点击 2游戏人员  这是做模拟外挂的必备知识,不管手机还是电脑游戏,尤其副本 准备模块 代码如下: 实现了一个最简单的输入密码,enter进入的登录过程 ...

  4. linux网络开发者定位问题常用工具和命令总结

    本文章来自我的微信个人技术公众号---网络技术修炼,公众号中总结普及网络基础知识,包括基础原理.网络方案.开发经验和问题定位案例等,欢迎关注. Linux网络开发者面临的问题往往比较复杂,因此需要使用 ...

  5. 记一次python写爬虫爬取学校官网的文章

    有一位老师想要把官网上有关数字化的文章全部下载下来,于是找到我,使用python来达到目的 首先先查看了文章的网址 获取了网页的源代码发现一个问题,源代码里面没有url,这里的话就需要用到抓包了,因为 ...

  6. .Net 6.0 部署Linux+Nginx +PM2教程

    今天带大家将本地.Net6.0项目部署到Linux系统中,其中有用到Nginx反向代理和PM2进程管理工具,希望本偏文章能对你有所帮助,成为你成功路上的垫脚石! 背景: 在.Net 5.0横空出世之后 ...

  7. Qt开发技术:Q3D图表开发笔记(三):Q3DSurface三维曲面图介绍、Demo以及代码详解

    前言   qt提供了q3d进行三维开发,虽然这个框架没有得到大量运用也不是那么成功,性能上也有很大的欠缺,但是普通的点到为止的应用展示还是可以的.  其中就包括华丽绚烂的三维图表,数据量不大的时候是可 ...

  8. 苹果怎么查看UDID iPhone/iPad查看UDID教程【详解】

      在开发iPhone和iPad软件的时候,要使用UDID来做真机测试,那么如何查看iPhone或者iPad的UDID呢?下面介绍三种最简单的查看UDID的方法,供大家参考!下面就详情来看看. 1.使 ...

  9. 3.2 构造器、this、包机制、访问修饰符、封装

    构造器 构造器:在实例化的一个对象的时候会给对象赋予初始值,因此我们可以通过修改构造器,来改变对象的初始值,构造器是完成对象的初始化,并不是创建对象 我们也可以创建多个构造器实现不同的初始化,即构造器 ...

  10. Prometheus监控之SNMP Exporter介绍和数据展现

    由于技术能力有限,文章仅能进行简要分析和说明,如有不对的地方,请指正,谢谢. 1 SNMP协议介绍 SNMP协议全称是:Simple Network Management Protocol,译为简单网 ...