在学习Scala的过程当中,总会碰到一些注解:java
// Predef.scala @inline def implicitly[T](implicit e: T) = e @deprecated("Use `sys.error(message)` instead", "2.9.0") def error(message: String): Nothing = sys.error(message) // Spark RDD.scala abstract class RDD[T: ClassTag]( @transient private var sc: SparkContext, ....)
通常来讲,注解能够做用于vals, vars, defs, classes, objects, traits 和 types甚至是表达式的后面。编程
import scala.reflect.runtime.{ universe => ju } def meth[A: ju.TypeTag](xs: List[A]) = xs match { case strList: List[String @ unchecked] if ju.typeTag[A].tpe =:= ju.typeOf[String] => "list of Strings" case barList: List[Bar @ unchecked] if ju.typeTag[A].tpe =:= ju.typeOf[Bar] => "list of Bar" }
咱们知道List[T]在运行时会被类型擦除,至关于变成List。@unchecked 告诉compiler不要去检查这个,不然就会报下面的warning。并发
non-variable type argument String in type pattern List[String] is unchecked since it is eliminated by erasure
另外, 注解实际上也是普通的类只不过编译器对其进行特殊的支持,因此咱们才能那样书写。好比说,咱们常见的序列号的注解。app
class SerialVersionUID(uid: Long) extends scala.annotation.StaticAnnotation @SerialVersionUID(13567156) class B {} @deprecated("use newShinyMethod() instead", "since 2.3") def bigMistake() = //... bigMistake scalac -deprecation Deprecation2.scala warning: method bigMistake in class B is deprecated: use newShinyMethod() instead println(bigMistake) ^ one warning found
实际上这个注解或是关键字,大多用于被并发访问的共享变量。在JVM内存模型中happens-before规则有一条就是volatile变量法则(有兴趣能够阅读Java并发编程实践 第16章Java内存模型),对于volatile变量,同一变量的写操做老是先于读操做。学习
class Person(@volatile var name: String) { def set(changedName: String) { name = changedName } }
这个注解是与尾递归优化有关的。优化
// 阶乘 def factorial(n: Int) = { @tailrec def go(n: Int, acc: Int): Int = { if (n <=0) acc else go(n-1, acc * n) // 尾递归,顾名思义方法的调用也必须出如今返回值的位置 } go(n, 1) }
通常是在模式匹配的时候用到的,告诉编译器有些地方不用"检查"了。如前所述,List[String @ unchecked]。ui
这个注解通常用于序列化的时候,标识某个字段不用被序列化。spa
import java.io.{ FileOutputStream, FileInputStream } import java.io.{ ObjectOutputStream, ObjectInputStream } class Hippie(val name: String, @transient val age: Int) extends Serializable object Serialization { val fos = new FileOutputStream("hippie.txt") val oos = new ObjectOutputStream(fos) val p1 = new Hippie("zml", 34) oos.writeObject(p1) oos.close() } object Deserialization extends App { val fis = new FileInputStream("hippie.txt") val ois = new ObjectInputStream(fis) val hippy = ois.readObject.asInstanceOf[Hippie] println(hippy.name) println(hippy.age) ois.close() } 运行以后的结果 zml 0
因为age被标记为@transient,在反序列化的时候,就获取不到原始值了因此被赋值为默认值。scala
这个注解,在Scala.Predef中见到过一次。官方文档中的解释跟没说同样, 却是StackOverflow上一个的答案,我的以为比较能说明做用。code
Instead of a function call resulting in parameters being placed on the stack and an invoke operation occurring, the definition of the function is copied at compile time to where the invocation was made, saving the invocation overhead at runtime.
大体的意思就是@inline可以避免方法的参数被放到栈上,以及"显示的调用"。由于编译器在编译的时候会将整个方法复制到它被调用的地方。
http://stackoverflow.com/questions/4593710/when-should-i-and-should-i-not-use-scalas-inline-annotation