S-JIS[2011-02-22/2012-10-20] 変更履歴

Scalaアノテーション

Scalaのアノテーション(注釈)のメモ。


概要

アノテーションはコンパイラーやツールに解釈させる為の印。

アノテーションを使うときはJavaと同様に「@」を付けて使用する。
アノテーションを作るときはJavaとは違ってAnnotationクラスを継承したクラスとして作成する。


アノテーションの使用方法

アノテーションを指定するには、(クラス等と同様に)そのまま完全修飾名で使うか、インポートして使う。

@scala.annotation.tailrec
def f(n:Int) = 〜
import scala.annotation.tailrec
@tailrec
def f(n:Int) = 〜

引数のあるアノテーションでは、丸括弧を付けて引数を書く。
引数が複数あるときは、値をカンマで区切って列挙するか、「引数名=値」で指定する。
(コンストラクターの引数指定と同様)

@deprecated("非推奨です")
class A
@deprecated(message="非推奨です")
class A

アノテーションを付けられる場所

Scalaのアノテーションは、以下のような所に付けられる。
(参考→Javaのアノテーションが付けられる場所

主な場所 備考
class
@a class クラス名 extends 親クラス @a with トレイト @a {
}
親クラス(トレイト)からextends・ミックスインする場合、
クラス名・トレイト名の後ろに付けられる。
classだけでなく、traitobjectも同様。
class クラス名(@a 引数:型 @a)
コンストラクターの引数では、
引数名の前と型名の後ろに付けられる。
class クラス名[@a T]
型パラメーターに対するアノテーション。
type
@a type 別名 = クラス @a with トレイト @a
 
val
@a val 変数名 = 値
@a protected val 変数名 = 値
val 変数名:型 @a = 値
変数の型に付ける場合は、型名を省略できない。
varも同様。
def
@a def メソッド名() = 本体
 
def メソッド名(@a 引数:型 @a) = 本体
メソッドの引数では、
引数名の前と型名の後ろに付けられる。
def メソッド名():戻り型 @a = 本体
メソッドの戻り値の型に付ける場合は、
型名を省略できない。

Javaでは同一の場所に同じアノテーションを複数指定する事は出来ないが、Scalaでは可能。


代表的なアノテーション

標準で用意されているアノテーション。

scalaパッケージ直下のアノテーションは自動的にインポートされているので、そのまま使用可能。
それ以外のアノテーションは完全修飾名で指定するかインポートする必要がある。

アノテーション名 備考
scala throws
@throws(classOf[java.io.IOException])
def f() = 〜
Javaのthrowsに相当。
これを付けると、生成されるバイトコード(classファイル)にthrows宣言が追加される。
Javaから当該メソッドを呼び出したい場合に使用する。
scala serializable
@serializable
@SerialVersionUID(123L)
class A {
  @transient val v = 456
}
JavaのSerializableインターフェースに相当。
シリアライズ可能である事を示す。
scala SerialVersionUID JavaのserialVersionUIDフィールドに相当。
scala transient Javaのtransientに相当。
シリアライズしないフィールドである事を示す。
scala cloneable
@cloneable
class A {
  override def clone() = super.clone().asInstanceOf[A]
}
JavaのCloneableインターフェースに相当。
クローンが作成可能である事を示す。
(@cloneableを付けていないと、super.clone()を呼び出した時にCloneNotSupportedExceptionが発生する)
scala deprecated
@deprecated("非推奨です")
def f() = "hello, world"
Javaの@Deprecatedアノテーション(あるいはJavadocの@deprecatedタグ)に相当。
非推奨なクラス・メソッド・フィールドである事を示す。
@deprecated("非推奨です", "2.0")
def f() = "hello, world"
Scala2.9では、第2引数(どのバージョンから非推奨になったか)を指定しないと警告が出る。[2012-10-20]
scala native   Javaのnativeに相当。
scala volatile   Javaのvolatileに相当。
scala unchecked
def f(x: Option[Int]) = (x: @unchecked) match {
  case Some(y) => y
//case None    =>
}
match式においてcaseが足りなくてMatchErrorが出る可能性がある場合にコンパイル警告が出るが、それを抑止する。
scala.annotation switch
(c: @switch) match {
  case ' ' | '\t' => "blank"
  case _          => "other"
}
match式をJavaのswitch文に展開する。
Scala2.8以降。
scala.annotation tailrec
[2011-02-24]
@tailrec
def f(n: Int, s:Int): Int = {
  if (n <= 0) s else f(n-1, s+n)
}
末尾再帰を最適化する。
scala inline
noinline
  メソッドをインライン化するかどうかの制御らしいが…。
scala specialized
[2011-02-24]
class A[@specialized(Int, Long) T] {
  def f(n: T) = n
}
通常のクラスの他に、アノテーションで指定したプリミティブ型に特化したクラスを生成する。
Scala2.8以降。
scala.reflect BeanProperty
class A(
  @BeanProperty var zzz:Int
)
class B {
  @BeanProperty var zzz = 123
}
JavaBeans形式のセッター・ゲッターメソッド(setZzz()・getZzz())が生成される。
@BooleanBeanPropertyだとゲッターがisZzz()になる。

Scala目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま