拓展新的语法
我们来看看 yew
中的过程宏 html!
,它可以帮助开发者在Rust中编写前端页面(我们将在后面看程序性宏)。下面是一个关于如何调用这个宏的例子:
use yew::html;
html! {
<div>
<div class="panel">
{ "Hello, World!" }
</div>
</div>
}
宏调用看起来一点也不像Rust,是不是?但是 html!
将其调用的代码解析为类似于 HTML 的语言,并生成了一个叫做 虚拟DOM 的层级结构。由此产生的扩展代码是纯粹的Rust,而且它是可以被rustc编译:
VTag::new(
"div",
vec![VTag::new("div", ...)],
);
这就是宏如何将另一种语言嵌入到Rust中的例子。
⚠️ 宏主体中的空白被消除了,所以没有办法写出,比如说,注入Python这样的语言的宏。下面是更多关于宏如何有助创建自定义语法的例子:
- Collection:如标准库中的vec。
- 文本格式化:由
println/format
这样的宏呈现(println!
是一个声明宏,它扩展到rustc中包含的过程宏format_args_nl
)。
请注意,禁止的符号在过程宏中不能使用。总而言之,程序宏中只能包含Rust中已经允许的符号。
减少模版代码
为了说明这一点,我们使用一个 struct
例子。通常情况,struct
有许多 trait
需要实现:
struct Foo { x: i32, y: i32 }
impl Copy for Foo { ... }
impl Clone for Foo { ... }
impl Ord for Foo { ... }
impl PartialOrd for Foo { ... }
impl Eq for Foo { ... }
impl PartialEq for Foo { ... }
impl Debug for Foo { ... }
impl Hash for Foo { ... }
这里派上用场的是 derive
,它是一个过程宏。上述 trait
可以使用rustc的 derive宏(#[derive]
) 来重写。
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug, Hash, Default)]
struct Foo { x: i32, y: i32 }
每一次 derive 都会在原始结构的基础上产生一个特定的 impl block
。
过程宏
从本质上讲,过程宏 是一个在编译时执行的Rust函数。这类函数属于一个特殊的 crate,并标有 proc-macro
标记。详细的代码在 Cargo.toml 中:
[package]
name = "my-proc-macro"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
TODO!!!
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。