Scala基礎之注解(annotation


在學習Scala的過程中,總會碰到一些注解:

// 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 

另外, 注解實際上也是普通的類只不過編譯器對其進行特殊的支持,所以我們才能那樣書寫。比如說,我們常見的序列號的注解。

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 

@volatile

實際上這個注解或是關鍵字,大多用於被並發訪問的共享變量。在JVM內存模型中happens-before規則有一條就是volatile變量法則(有興趣可以閱讀Java並發編程實踐 第16章Java內存模型),對於volatile變量,同一變量的寫操作總是先於讀操作。

class Person(@volatile var name: String) { def set(changedName: String) { name = changedName } } 

@tailrec

這個注解是與尾遞歸優化有關的。

// 階乘 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) } 

@Unchecked

一般是在模式匹配的時候用到的,告訴編譯器有些地方不用"檢查"了。如前所述,List[String @ unchecked]。

@transient

這個注解一般用於序列化的時候,標識某個字段不用被序列化。

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,在反序列化的時候,就獲取不到原始值了所以被賦值為默認值。

@inline

這個注解,在Scala.Predef中見到過一次。官方文檔中的解釋跟沒說一樣, 倒是StackOverflow上一個的答案,個人覺得比較能說明作用。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM