• 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 {
    

      

  • 相关阅读:
    JDK8的JVM内存模型小结
    揭开Service Mesh的神秘面纱
    通过Shell脚本读取properties文件中的参数时遇到 换行符的问题
    NodeJs+Express实现简单的Web增删改查
    SpringBoot之Thymeleaf模板引擎
    面向对象(下)
    内部类
    线程学习oneday
    Python-使用tkinter实现的Django服务进程管理工具
    Python-使用百度文字识别API实现的文字识别工具
  • 原文地址:https://www.cnblogs.com/xuesu/p/13888758.html
Copyright © 2020-2023  润新知