Scala之旅——注解

注解将元信息和定义关联起来。例如,注解方法前的@deprecated会使得编译器在该方法被调用时打印一条警告。

1
2
3
4
5
6
object DeprecationDemo extends App {
@deprecated("deprecation message", "release # which deprecates method")
def hello = "hola"

hello
}

上述代码可以通过编译但是编译器会打印一条警告:“there was one deprecation warning”。

注解子句用于其后的第一个定义或者声明。一个定义或者声明的前面可以出现不止一个注解子句,而它们的顺序并不重要。

确保编码正确的注解

某些注解会在条件不满足的情况下导致编译失败。例如,注解@tailrec可以确保一个方法是尾递归。尾递归可以使得内存需求是固定的。下面是该注解在计算阶乘的方法中的使用情况:

1
2
3
4
5
6
7
8
9
10
import scala.annotation.tailrec

def factorial(x: Int): Int = {

@tailrec
def factorialHelper(x: Int, accumulator: Int): Int = {
if (x == 1) accumulator else factorialHelper(x - 1, accumulator * x)
}
factorialHelper(x, 1)
}

factorialHelper方法拥有注解@tailrec,可以确保该方法的确是尾递归的。如果我们按照下面的方式改变该方法的实现,则会编译失败:

1
2
3
4
5
6
7
8
9
import scala.annotation.tailrec

def factorial(x: Int): Int = {
@tailrec
def factorialHelper(x: Int): Int = {
if (x == 1) 1 else x * factorialHelper(x - 1)
}
factorialHelper(x)
}

我们将得到提示信息“Recursive call not in tail position”。

影响代码生成的注解

有些注解(如@inline)会影响代码的生成(即生成的jar文件跟不使用注解相比可能具有不同的字节大小)。内联(inlining)的意思是将方法体中的代码直接插入到调用的位置。这样生成的字节码会更长,但是运行会更快。使用注解@inline无法确保一个方法会变成内联的,当且仅当通过了关于生成代码规模的一些尝试之后,编译器会将该方法变成内联的。

Java注解

在写与Java进行互操作的Scala代码时,在注解的语法上有些不同点需要注意。

注:在使用Java注解时必须带上选项-target:jvm-1.8

Java可以通过注解的形式来拥有用户自定义的元数据。注解的关键特性是依赖于对指定的名-值对进行初始化。例如我们需要一个注解来追踪某些类的来源,可能会这样来定义:

1
2
3
4
@interface Source {
public String URL();
public String mail();
}

接下来可以这样来使用:

1
2
3
@Source(URL = "http://coders.com/",
mail = "support@coders.com")
public class MyClass extends HisClass ...

在Scala中使用注解像是在调用构造器,要实例化一个Java注解需要指定参数名:

1
2
3
@Source(URL = "http://coders.com/",
mail = "support@coders.com")
class MyScalaClass ...

当注解仅有一个元素的时候这种语法便有点繁琐。所以习惯上,如果元素名称被指定为value,那么在Java中可以用类似于构造器的语法:

1
2
3
4
@interface SourceURL {
public String value();
public String mail() default "";
}

然后这样使用:

1
2
@SourceURL("http://coders.com/")
public class MyClass extends HisClass ...

这个例子中,Scala的用法也是类似的:

1
2
@SourceURL("http://coders.com/")
class MyScalaClass ...

这里mail元素被指定了一个默认值,所以不需要为它显式提供一个值。然而,如果需要给它提供值,在Java中不能混搭这两种形式:

1
2
3
@SourceURL(value = "http://coders.com/",
mail = "support@coders.com")
public class MyClass extends HisClass ...

Scala则在这方面提供了更多的灵活性:

1
2
3
@SourceURL("http://coders.com/",
mail = "support@coders.com")
class MyScalaClass ...
小鹏 wechat
公众号:数据Man
0%