注解
注解(Annotation)是一种只用在声明上的特殊语法,它用来给编译器或者运行时提供额外信息来实现特定的功能。
注解最基本的语法示例如下:
@Annotation1[arg1, arg2]
@Annotation2
class Foo {}
注解可以用在不同的声明上。
其语法规格定义为:
annotationList: annotation+;
annotation
: '@' (identifier '.')* identifier ('[' annotationArgumentList ']')?
;
annotationArgumentList
: annotationArgument (',' annotationArgument)* ','?
;
annotationArgument
: identifier ':' expression
| expression
;
注解和宏调用使用了一样的语法。由于宏处理的阶段比注解更早,编译器在解析时会先尝试将该语法当作宏处理。如果作为宏不成功则继续尝试将该语法作为注解处理。如果两种处理方式都不成功则应该编译报错。
自定义注解
自定义注解机制用来让反射获取标注内容,目的是在类型元数据之外提供更多的有用信息,以支持更复杂的逻辑。
自定义注解可以用在类型声明、成员变量声明、成员属性声明、成员函数声明、构造函数声明、构造器声明、(前面提到的函数里的)函数参数声明上。
开发者可以通过自定义类型标注 @Annotation
方式创建自己的自定义注解。
@Annotation
只能修饰 class
,并且不能是 abstract
或 open
或 sealed
修饰的 class
。
当一个 class
声明它标注了 @Annotation
,那么它必须要提供至少一个 const init
函数,否则编译器会报错。
下面是一个自定义注解的例子:
@Annotation
public class CustomAnnotation {
let name: String
let version: Int64
public const init(name: String, version!: Int64 = 0) {
this.name = name
this.version = version
}
}
// use annotation
@CustomAnnotation["Sample", version: 1]
class Foo {}
注解信息需要在编译时生成信息绑定到类型上,自定义注解在使用时必须使用 const init
构建出合法的实例。
我们规定:
- 注解声明语法与声明宏语法一致,后面的
[]
括号中需要按顺序或命名参数规则传入参数,且参数必须是 const 表达式。 - 对于拥有无参构造函数的注解类型,声明时允许省略括号。
@Annotation
public class MyAnnotation { ... }
@MyAnnotation // ok
class Foo {}
对于同一个注解目标,同一个注解类不允许声明多次,即不可重复。
编译器不承诺生成的多个 Annotation
元数据的顺序跟代码中 Annotation
的标注顺序保持一致。
@MyAnnotation
@MyAnnotation // error
class Foo {}
@MyAnnotation
@MyAnnotation2
class Bar {}
Annotation
不会被继承,因此一个类型的注解元数据只会来自它定义时声明的注解。如果需要父类型的注解元数据信息,需要开发者自己用反射接口查询。
@BaseAnno
open class Base {}
@InterfaceAnno
interface I {}
@SubAnno
class Sub <: Base & I {} // Sub has only SubAnno annotation information.
自定义注解可以限制自己可以使用的位置,这样可以减少开发者的误用,这类注解需要在声明 @Annotation
时标注 target 参数。
target 参数需要以变长参数的形式传入该自定义注解希望支持的位置,target 接收的参数是一个 Array<AnnotationKind>
。
可以限制的位置包括:
- 类型声明(class、struct、enum、interface)
- 成员函数/构造函数中的参数
- 构造函数声明
- 成员函数声明
- 成员变量声明
- 成员属性声明
public enum AnnotaitionKind {
| Type
| Parameter
| Init
| MemberProperty
| MemberFunction
| MemberVariable
}
@Annotation[target: [Type, MemberFunction]]
class CustomAnnotation{}
@Annotation
class SubCustomAnnotation{}
@Annotation[target: []]
class MyAnno{}
当没有限定 target 的时候,该自定义注解可以用在以上全部位置。当限定 target 时,只能用在声明的列表中。