一、什么是属性
Attributes,属性,这个名词可在不少的语言中都有。属性有不同的表述的含义,比如常见的Getter和Setter,此类属性在Java、c#等语言中都广泛存在。另外一种就是将要讨论的作为一种元数据(Meta)的表述,是一种通用的用于表达元数据的特性,借鉴ECMA-334(C#)的语法来实现ECMA-335中描述的Attributes。在Rust中,属性只能应用于Item(元素、项)。
二、Rust属性
Rust属性的基本格式如下:
#[name(arg1, arg2 = "param")] //比如前文FFI中的#[no_mangle]表示关闭Rust的更名机制 #[test]表示这是测试
它是由一个#开启,后面紧接着一个[],里面便是属性的具体内容,它可以有如下几种写法:
单个标识符代表的属性名,如#[unix]
单个标识符代表属性名,后面紧跟着一个=,然后再跟着一个字面量(Literal),组成一个键值对,如#[link(name = “openssl”)]
单个标识符代表属性名,后面跟着一个逗号隔开的子属性的列表,如#[cfg(and(unix, not(windows)))]
在#后面还可以紧跟一个!,比如#![feature(box_syntax)],这表示这个属性是应用于它所在的这个Item。而如果没有!则表示这个属性仅应用于紧接着的那个Item。
前面提到了,在Rust中属性只能用于Item,它有以下七个主要用途::
1、条件编译代码
2、设置 crate 名称、版本和类型
3、禁用 lint 警告
4、启用编译器的特性(如宏、全局导入等)
5、连接到一个非 Rust 语言的库
6、标记函数作为单元测试
7、标记函数作为基准测试的某个部分
表现在Rust中可以在模块、crate 或者项中进行应用:
在整个 crate 应用的语法为:
#![crate_attribute] (有感叹号!)
在模块或者项应用的语法为:
#[item_attribute] (无感叹号)
属性可以接收参数,其语法形式如下:
#[attribute = "value"]
#[attribute(key = "value")]
#[attribute(value)]
#[attribute(value1, value2, value3, value4, value5)]
明白了规则再学习就很简单了。
三、应用
在Rust中,属性的应用非常广泛,主要的应用场景有:
1、extern crate声明
2、use声明
3、模块(模块是一个Item的容器)
4、函数
5、type定义
6、结构体定义
7、枚举类型定义
8、常量定义
9、静态变量定义
10、Trait定义
11、实现(Impl)
这里只对个别的进行实例说明,更具体的请参考一下Rust的相关说明文档.
// 为这个crate开启box_syntax这个新特性
#![feature(box_syntax)]
// 这是一个单元测试函数
#[test]
fn test_foo() {
/* ... */
}
// 条件编译,只会在编译目标为Linux时才会生效
#[cfg(target_os="linux")]
mod bar {
/* ... */
}
// 为以下的这个type定义关掉non_camel_case_types的编译警告
#[allow(non_camel_case_types)]
type int8_t = i8;
//应用于FFI
#[link(name = "readline")]
extern {
}
#[link(name = "CoreFoundation", kind = "framework")]
extern {
}
//应用于宏
#[macro_use(debug, trace)]
extern crate log;
//应用于函数
// 把`my_main`作为主函数
#[main]
fn my_main() {
}
// 把`plugin_registrar`作为此编译器插件的入口函数
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("rn", expand_rn);
}
// 把`entry_point`作为入口函数,不再执行标准库中的初始化流程
#[start]
fn entry_point(argc: isize, argv: *const *const u8) -> isize {
}
// 定义一个单元测试
// 这个单元测试一定会panic
#[test]
#[should_panic]
fn my_test() {
panic!("I expected to be panicked");
}
// 这个函数很可能是不会执行的,
// 所以优化的时候就换种方式
#[cold]
fn unlikely_to_be_executed() {
}
其它的都可以在Rust社区和相关文档书籍中查找。
- 代码主要来自《Rust Primer》
四、总结
如果纵向学习概念不清晰,总是分不清来龙去脉,可以考虑横向比较一下,有比较才会更精准的把握不同。就和人的漂亮和丑一样,是个相对概念,没有对比,就不会有伤害。
努力吧,归来的少年!