< 返回版块

yooocen 发表于 2019-11-04 00:18

Tags:属性,注解

我仔细阅读了rust的英文教程,发现了rust的属性的用法还挺有趣的

以下是我截取的使用wasm_bindgen属性的一个例子

#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

以下是我摘下来的7个主要用处

  1. conditional compilation of code
  2. set crate name, version and type (binary or library)
  3. disable lints (warnings)
  4. enable compiler features (macros, glob imports, etc.)
  5. link to a foreign library
  6. mark functions as unit tests
  7. mark functions that will be part of a benchmark

但是这个语法对于我来说也是相当困惑,有以下两个问题

  1. 我可以定义自己的属性吗?
  2. 从编译层面它是怎么起作用的,有源代码之类的看吗?

评论区

写评论
12101111 2019-11-05 15:49

stable是rustc对内置库(std,core,alloc,proc_macro)使用的一个属性,会被rustc解析,表面这个功能是在某版本号之后稳定的,对应的还有unstable,只有当rustc是nightly版本时并且使用#![feature()]才能使用unstable的功能. 所有未稳定的功能在https://doc.rust-lang.org/nightly/unstable-book/the-unstable-book.html

作者 yooocen 2019-11-05 00:43

另外,我还有一个疑问,我翻看了proc_macro的源码,看到了一下一个属性 #[stable(feature = "proc_macro_lib", since = "1.15.0")]

我在下面的文档后面列出的所有内建属性中没有找到 stable的定义 https://doc.rust-lang.org/reference/attributes.html

所以,这个是自定义的属性吗

作者 yooocen 2019-11-05 00:36

感谢楼上的回复,是我理解错了,内建的属性和那个#[wasm_bindgen]是有本质区别的,后者是宏的一种,我又看了文档,原来过程宏有三种,也就是楼上说的那三种,用我自己的话来理解就是 像函数一样的宏(就是后面带了感叹号那种,就像println!),一种就是我上面理解错的那种:像属性一样的宏,第三种我还没有见过,我理解是自定义的衍生宏,不知道还有人可以给一下具体使用它的例子吗?

我还摘了一些源码出来

#[proc_macro_attribute]
pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
    match wasm_bindgen_macro_support::expand(attr.into(), input.into()) {
        Ok(tokens) => {
            if cfg!(feature = "xxx_debug_only_print_generated_code") {
                println!("{}", tokens);
            }
            tokens.into()
        }
        Err(diagnostic) => (quote! { #diagnostic }).into(),
    }
}

再次感谢楼上的回复!

12101111 2019-11-04 14:14

你说的7个功能是rustc内置的,和#[wasm_bindgen]这种不是一回事.

#[wasm_bindgen]这种自定义的属性属于过程宏(proc-macro),是rustc的一个功能(严格地说不是rust语言的语法)

过程宏位于单独的crate中(Cargo.toml中有proc-macro = true),被编译成链接到rustc的so/dll,编译源代码的时候被rustc加载,然后处理被修饰的AST(即proc_macro::TokenStream类型),返回处理后的AST,然后rustc继续编译.

理论上过程宏可以把被修饰的源代码修改成任意想要的代码

rustc内置一个proc-macro,就像core和std一样.proc-macro提供了编写新的过程宏的接口,以及rust token类型的定义,文档在https://doc.rust-lang.org/proc_macro/

过程宏的crate里需要定义处理TokenStream的函数,这些函数本身需要被一些属性修饰,表面他们的使用方式

  1. function-like macros,比如 some_macro!,需要使用 #[proc_macro]修饰
  2. macro attributes.比如#[wasm_bindgen],使用 #[proc_macro_attribute]修饰
  3. custom derive attributes,比如比如#[derive(Parse)],使用#[proc_macro_derive]修饰.

使用方法是

extern crate proc_macro;
#[proc_macro_derive(MyDerive)]
pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
//处理TokenStream
}

要写一个过程宏可以参考: syn,quote,proc-macro2 这些crate,因为内置的proc-macro功能很少

proc-macro2是第三方库,能在不同编译器版本之间保证proc-macro的兼容性

syn能把proc_macro::TokenStream解析成自定义的struct,qutoe实现了类似macro_rules!的语法,但是返回的结果是TokenStream

wasm_bindgen的源码在:

https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro

https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support

1 共 4 条评论, 1 页