示例:
fn add_one(x: i32) -> i32 {
x + 1
}
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
fn main() {
let answer = do_twice(add_one, 5);
String::from("hello");
println!("The answer is: {}", answer);
}
- 不同于闭包,fn 是一个类型而不是一个 trait,所以直接指定 fn 作为参数而不是声明一个带有 Fn 作为 trait bound 的泛型参数。
- 函数指针实现了所有三个闭包 trait(Fn、FnMut 和 FnOnce),所以总是可以在调用期望闭包的函数时传递函数指针作为参数。
- 因为闭包是 trait,需要使用 DST
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
Box::new(|x| x + 1)
}
在一个文件里调用宏 之前 必须定义它,或将其引入作用域,而函数则可以在任何地方定义和调用。
Rust 最常用的宏形式是 声明宏(declarative macros)。它们有时也被称为 “macros by example”、“macro_rules! 宏
” 或者就是 “macros”。
原理:
宏将一个值和包含相关代码的模式进行比较;此种情况下,该值是传递给宏的 Rust 源代码字面值,模式用于和传递给宏的源代码进行比较,同时每个模式的相关代码则用于替换传递给宏的代码。所有这一切都发生于编译时。
举例:
使用 vec!
宏来生成一个给定值的 vector:
let v: Vec<u32> = vec![1, 2, 3];
vec!
稍微简化的定义:
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
注意:标准库中实际定义的 vec! 包括预分配适当量的内存的代码。这部分为代码优化,为了让示例简化,此处并没有包含在内。
说明:
-
用
#[macro_export]
注解说明宏应该是导入的,用macro_rules!
和宏名称开始宏定义,且所定义的宏并 不带 感叹号。名字后跟大括号表示宏定义体,在该例中宏名称是 vec 。 -
vec!
宏的结构和 match 表达式的结构类似。此处有一个单边模式( $( $x:expr ),* )
,后跟 => 以及和模式相关的代码块。如果模式匹配,该相关代码块将被执行。假设这是这个宏中唯一的模式,则只有这一种有效匹配,其他任何匹配都是错误的。更复杂的宏会有多个单边模式。 -
模式片段什么意思?首先,一对括号包含了整个模式。接下来是美元符号(
$
),后跟一对括号,捕获了符合括号内模式的值以用于替换后的代码。$()
内则是$x:expr
,其匹配 Rust 的任意表达式,并将该表达式记作$x
。$()
之后的逗号说明一个可有可无的逗号分隔符可以出现在 $() 所匹配的代码之后。紧随逗号之后的*
说明该模式匹配零个或更多个*
之前的任何模式。 -
替换该宏调用所生成的代码会是下面这样:
let mut temp_vec = Vec::new();
temp_vec.push(1);
temp_vec.push(2);
temp_vec.push(3);
temp_vec
示例:
文件名:hello_macro_derive/src/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 {
// 将 Rust 代码解析为语法树以便进行操作
let ast = syn::parse(input).unwrap();
// 构建 trait 实现
impl_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()
}
另一个项目中,添加依赖
[dependencies]
hello_macro = { path = "../hello_macro" }
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
文件名:src/main.rs
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;
fn main() {
Pancakes::hello_macro();
}
定义宏:
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
使用宏:
#[route(GET, "/")]
fn index() {
定义宏:
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
使用宏:
let sql = sql!(SELECT * FROM posts WHERE id=1);