元编程技术大概分为:
- 简单文本替换
- 类型模板
- 反射
- 语法扩展
- 代码自动生成
Rust语言通过反射和AST语法扩展两种手段来支持元编程。
反射
反射机制一般是指程序自我访问、检测和修改其自身状态或行为的能力。Rust标准库提供了std::any::Any来支持运行时反射。可以先看下代码结构:
Any
定义:
|
|
- 该 trait 加上了
'static
生命周期限定,意味着该 trait 不能被非静态生命周期的类型实现。impl<T: 'static + ?Sized> Any for T
表示 Rust 中满足'static
生命周期的类型均实现了它。 type_id
方法返回TypeId
类型,代表 Rust 中某个类型的全局唯一标识,它是在编译时生成的。
|
|
- 每个
TypeId
都是一个“黑盒”,不能检查其内部内容,但是允许复制、比较、打印等操作。TypeId
当前仅适用于归因于'static
的类型,但是可以在 future 中消除此限制。
通过 is 函数判断类型
|
|
- 因为
Any
是一个 trait ,所以这里的is
方法的&self
必然是一个 trait 对象。 TypeId::of
函数用来获取类型T
的全局唯一标识符t
。
|
|
输出结果:
|
|
TypeId
是一个结构体,其字段t
存储了一串数字,这就是全局唯一类型标识符,实际上是 u64 类型。代表唯一标识符的这串数字,在不同的编译环境中,产生的结果是不同的。所以在实际开发中,最好不要将TypeId
暴露到外部接口中被当作依赖。
转换到具体类型
Any 提供了 downcast_ref
和 downcast_mut
两个成对的泛型方法,用于将泛型T向下转换为具体的类型,返回值分别是 Option<&T>
和 Option<&mut T>
类型。
|
|
非静态生命周期类型
|
|
- 带引用字段的结构体
Unstatic<'a>
,其生命周期不是静态的,编译会报错。
修改:
|
|
Any 的应用
Remark
在2018 Edition 中,以下语句不会报错:
|
|
但是在2021 Edition中,必须加上 dyn
。
|
|
宏系统
Rust编译过程:
声明宏
宏展开命令: cargo rustc – -Z unstable-options –pretty=expanded
示例1:
|
|
支持token类型:
|
|
hashmap 1.0
|
|
hashmap 2.0:可以匹配结尾有逗号
|
|
hashmap 3.0
|
|
hashmap 4.0 : 节省存储空间
|
|
hashmap 5.0:将声明宏放在一起
|
|
示例:
|
|
- 注意这里会报错,宏里面的
a
变量是局部的。
过程宏
过程宏三件套:
介绍:
- Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree of Rust source code. 将 token 流转换成语法树。
- quote: This crate provides the
quote!
macro for turning Rust syntax tree data structures into tokens of source code. 将语法树转换成 token 源码。 - proc-macro2 比 proc-macro 更加的灵活。TokenStream API接口。
|
|
参考资料
- 《Rust编程之道》