1
1
---
2
2
layout : tour
3
- title : Annotations
3
+ title : 注解
4
4
5
5
discourse : false
6
6
@@ -13,3 +13,114 @@ language: zh-cn
13
13
next-page : default-parameter-values
14
14
previous-page : by-name-parameters
15
15
---
16
+
17
+ 注解将元信息与定义相关联。 例如,方法之前的注解 ` @deprecated ` 会导致编译器在该方法被使用时打印警告信息。
18
+ ```
19
+ object DeprecationDemo extends App {
20
+ @deprecated("deprecation message", "release # which deprecates method")
21
+ def hello = "hola"
22
+
23
+ hello
24
+ }
25
+ ```
26
+ 这个程序可以编译,但编译器将打印一个警告信息: "there was one deprecation warning"。
27
+
28
+ 注解作用于其后的第一个定义或声明。 在定义和声明之前可以有多个注解。 这些注解的顺序并不重要。
29
+
30
+ ## 确保编码正确性的注解
31
+ 如果不满足条件,某些注解实际上会导致编译失败。 例如,注解 ` @tailrec ` 确保方法是 [ 尾递归] ( https://en.wikipedia.org/wiki/Tail_call ) 。 尾递归可以保持内存需求不变。 以下是它在计算阶乘的方法中的用法:
32
+ ``` tut
33
+ import scala.annotation.tailrec
34
+
35
+ def factorial(x: Int): Int = {
36
+
37
+ @tailrec
38
+ def factorialHelper(x: Int, accumulator: Int): Int = {
39
+ if (x == 1) accumulator else factorialHelper(x - 1, accumulator * x)
40
+ }
41
+ factorialHelper(x, 1)
42
+ }
43
+ ```
44
+ 方法 ` factorialHelper ` 使用注解 ` @tailrec ` 确保方法确实是尾递归的。 如果我们将方法 ` factorialHelper ` 的实现改为以下内容,它将编译失败:
45
+ ```
46
+ import scala.annotation.tailrec
47
+
48
+ def factorial(x: Int): Int = {
49
+ @tailrec
50
+ def factorialHelper(x: Int): Int = {
51
+ if (x == 1) 1 else x * factorialHelper(x - 1)
52
+ }
53
+ factorialHelper(x)
54
+ }
55
+ ```
56
+ 我们将得到一个错误信息 "Recursive call not in tail position".
57
+
58
+
59
+ ## 影响代码生成的注解
60
+ 像 ` @inline ` 这样的注解会影响生成的代码(即你的 jar 文件可能与你没有使用注解时有不同的字节)。 内联表示在调用点插入被调用方法体中的代码。 生成的字节码更长,但有希望能运行得更快。 使用注解 ` @inline ` 并不能确保方法内联,当且仅当满足某些生成代码大小的启发式算法时,它才会触发编译器执行此操作。
61
+
62
+ ### Java 注解 ###
63
+ 在编写与 Java 互操作的 Scala 代码时,注解语法中存在一些差异需要注意。
64
+ ** 注意:** 确保你在开启 ` -target:jvm-1.8 ` 选项时使用 Java 注解。
65
+
66
+ Java 注解有用户自定义元数据的形式 ,参考 [ annotations] ( https://docs.oracle.com/javase/tutorial/java/annotations/ ) 。 注解的一个关键特性是它们依赖于指定 name-value 对来初始化它们的元素。 例如,如果我们需要一个注解来跟踪某个类的来源,我们可以将其定义为
67
+ ```
68
+ @interface Source {
69
+ public String URL();
70
+ public String mail();
71
+ }
72
+ ```
73
+
74
+ 并且按如下方式使用它
75
+
76
+ ```
77
+ @Source(URL = "http://coders.com/",
78
+ mail = "support@coders.com")
79
+ public class MyClass extends HisClass ...
80
+ ```
81
+
82
+ Scala 中的注解应用看起来像构造函数调用,要实例化 Java 注解,必须使用命名参数:
83
+
84
+ ```
85
+ @Source(URL = "http://coders.com/",
86
+ mail = "support@coders.com")
87
+ class MyScalaClass ...
88
+ ```
89
+
90
+ 如果注解只包含一个元素(没有默认值),则此语法非常繁琐,因此,按照惯例,如果将元素名称指定为 ` value ` ,则可以使用类似构造函数的语法在 Java 中应用它:
91
+ ```
92
+ @interface SourceURL {
93
+ public String value();
94
+ public String mail() default "";
95
+ }
96
+ ```
97
+
98
+ 然后按如下方式使用
99
+
100
+ ```
101
+ @SourceURL("http://coders.com/")
102
+ public class MyClass extends HisClass ...
103
+ ```
104
+
105
+ 在这种情况下, Scala 提供了相同的可能性
106
+
107
+ ```
108
+ @SourceURL("http://coders.com/")
109
+ class MyScalaClass ...
110
+ ```
111
+
112
+ ` mail ` 元素在定义时设有默认值,因此我们不需要显式地为它提供值。 但是,如果我们需要显示地提供值,我们则不能在 Java 中混合使用这两种方式:
113
+
114
+ ```
115
+ @SourceURL(value = "http://coders.com/",
116
+ mail = "support@coders.com")
117
+ public class MyClass extends HisClass ...
118
+ ```
119
+
120
+ Scala 在这方面提供了更大的灵活性
121
+
122
+ ```
123
+ @SourceURL("http://coders.com/",
124
+ mail = "support@coders.com")
125
+ class MyScalaClass ...
126
+ ```
0 commit comments