注解

注解(Annotation)是一种只用在声明上的特殊语法,它用来给编译器或者运行时提供额外信息来实现特定的功能。

注解最基本的语法示例如下:

@Annotation1[arg1, arg2]
@Annotation2
class Foo {}

注解可以用在不同的声明上。

其语法规格定义为:

annotationList: annotation+;

annotation
    : '@' (identifier '.')* identifier ('[' annotationArgumentList ']')?
    ;

annotationArgumentList
    : annotationArgument (',' annotationArgument)*  ','?
    ;

annotationArgument
    : identifier ':' expression
    | expression
    ;

注解和宏调用使用了一样的语法。由于宏处理的阶段比注解更早,编译器在解析时会先尝试将该语法当作宏处理。如果作为宏不成功则继续尝试将该语法作为注解处理。如果两种处理方式都不成功则应该编译报错。

自定义注解

自定义注解机制用来让反射获取标注内容,目的是在类型元数据之外提供更多的有用信息,以支持更复杂的逻辑。

自定义注解可以用在类型声明、成员变量声明、成员属性声明、成员函数声明、构造函数声明、构造器声明、(前面提到的函数里的)函数参数声明上。

开发者可以通过自定义类型标注 @Annotation 方式创建自己的自定义注解。

@Annotation 只能修饰 class,并且不能是 abstractopensealed 修饰的 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 构建出合法的实例。

我们规定:

  1. 注解声明语法与声明宏语法一致,后面的 [] 括号中需要按顺序或命名参数规则传入参数,且参数必须是 const 表达式。
  2. 对于拥有无参构造函数的注解类型,声明时允许省略括号。
@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 时,只能用在声明的列表中。