Rust Lang Book Ch.19 Function Pointers, Returing Closures, macros
Function Pointers
fn类型与Fn特性不一样,fn被称为function pointer,使用方法和Fn相似。但是在与C的FFI交互的时候,只能用fn。
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);
    println!("The answer is: {}", answer);
}
这里用了fn ToString::to_string而不是closure: |i|i.to_string()
    let list_of_numbers = vec![1, 2, 3];
    let list_of_strings: Vec<String> =
        list_of_numbers.iter().map(ToString::to_string).collect();
Returing Closure
可以直接返回fn作为返回值,但是若要返回Closure,因为Closure的大小是未定的,所以只能用Box<dyn 包裹。
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
    Box::new(|x| x + 1)
}
Macros
宏有三类:
1. #[derive],允许structs和enum上自动添加写好的代码
2. Attribute-like:在任意item上自定义属性
3. function-like:虽然像是函数,但是用token作为参数。
declarative macros
declarative macros允许编写一些类似match表达式的宏,以vec!的定义为例:
#[macro_export]
macro_rules! vec {
    ( $( $x:expr ),* ) => {
//这里有一个模式,如果被匹配,那么就会执行后面的代码快
//$x:expr匹配Rust的任意表达式
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push($x);
            )*
            temp_vec
        }
    };
}
#[macro_export]:如果没有这个注解,该宏就不能被用在作用域中
( $( $x:expr ),* ) =>。如果模式匹配,该相关代码块将被执行。$() 之后的逗号说明一个可有可无的逗号分隔符可以出现在 $() 所匹配的代码之后。紧随逗号之后的 * 说明该模式匹配零个或更多个 * 之前的任何模式。
procedural macros
更像函数,而不是直接替换。derive, attribute-like macros和function-like macros都是procedural macros。
derive
可以定义一个derive_a_macro库。
例如hello_macro。
1. 为自定义派生宏crate: hello_macro_derive的Cargo.toml添加必要依赖库’
[lib] proc-macro = true#编译器用来读取和操作Rust代码 [dependencies] syn = "0.14.4"#将代码解析为AST quote = "0.6.3"#将AST转化为Rust代码
2. 构建AST树,从树中取元素,构造新元素,写入AST树,转为rust代码
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 #name {
            fn hello_macro() {
                println!("Hello, Macro! My name is {}", stringify!(#name));
            }
        }
    };
    gen.into()
}
3. 使用
use hello_macro_derive::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;
fn main() {
    Pancakes::hello_macro();
}
[dependencies] =hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
Attribute-like macros
这些宏允许建立新的attribute,此外,attribute-like macros可以对函数,structs,enum都生效。
使用示例
#[route(GET, "/")]
fn index() {
定义示例
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
Function-like macros
宏的好处在于可以使用未知数量的参数,但是,只能遵循宏的语法。这些宏的输入是TokenStream,输出也是TokenStream,不过可以使用Rust代码来操作这些token。
使用示例
let sql = sql!(SELECT * FROM posts WHERE id=1
定义示例
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
                    
                
                
            
        
浙公网安备 33010602011771号