S-JIS[2011-01-08/2011-04-15] 変更履歴
Scalaの列挙型(定数群の定義)のメモ。
Javaではenumで列挙型を定義するが、ScalaではEnumerationクラスを継承したオブジェクトで定義する。
Scala | Java相当 | 備考 |
---|---|---|
object 列挙名 extends Enumeration { val 列挙子, 列挙子, … = Value } object E1 extends Enumeration { val A,B,C = Value } |
enum 列挙名 { 列挙子, 列挙子, … } enum E1 { A,B,C } |
列挙子に代入しているValueは、Enumeration内で定義されているValueメソッドの複数回呼び出し。 (これによって異なるインスタンスが返るので、列挙子同士を区別できる) 列挙子を区別する為に内部で採番される連番(ID)は0から開始する。 |
object E2 extends Enumeration(10) { val A,B,C = Value } |
内部で採番される連番(ID)を指定した番号から始める例。 | |
object E3 extends Enumeration { val A = Value(11) val B = Value(22) val C = Value(33) } |
IDを個別に割り当てる例。 | |
object E4 extends Enumeration { val A = Value("aaa") val B = Value("bbb") val C = Value("ccc") } object E4 extends Enumeration { val A = Value(11, "aaa") val B = Value(22, "bbb") val C = Value(33, "ccc") } object E4 extends Enumeration( "aaa", "bbb", "ccc" ) { val A,B,C = Value } |
列挙子の名前を個別に割り当てる例。 | |
object 列挙名 extends Enumeration { type 列挙名 = Value val 列挙子, 列挙子, … = Value } object E1 extends Enumeration { type E1 = Value val A,B,C = Value } |
enum 列挙名 { 列挙子, 列挙子, … } enum E1 { A,B,C } |
typeで名前を付けておくと、importして使う際に便利。 列挙名に代入しているValueと列挙子に代入しているValueは どちらも同じ名前だが、前者はクラスで後者はメソッド。 列挙名に代入しているValueは、Enumeration内で定義されているValueクラス。 列挙子に代入しているValueは、Enumeration内で定義されているValueメソッドの複数回呼び出し。 |
列挙型はオブジェクトなので、普通にオブジェクトとして使用する。
Scala | Java相当 | 備考 |
---|---|---|
object E1 extends Enumeration { val A,B,C = Value } scala> val e = E1.A e: E1.Value = A scala> if (e == E1.A) println("a") a |
enum E1 { A,B,C } final E1 e = E1.A; if (e == E1.A) 〜 |
|
object E1 extends Enumeration { type E1 = Value val A,B,C = Value } scala> import E1._ import E1._ scala> val e = A e: E1.Value = A scala> def f(e:E1) = println(e) f: (e: E1.E1)Unit |
enum E1 { A,B,C } import static E1.*; final E1 e = A; public void f(E1 e) { 〜 } |
列挙型オブジェクトのメンバーをimportすると 列挙子を接頭辞抜きで使用できるので便利。 また、列挙型オブジェクトの中で型名を定義しておくと その型名で変数を宣言できるので便利。 |
e match { case A => println("aho") case B => println("boo") case C => println("chu") } e match { case A | B => println("abu") case _ => } |
switch (e) { case A: System.out.println("aho");break; case B: System.out.println("boo");break; case C: System.out.println("chu");break; } switch (e) { case A: case B: System.out.println("abu");break; default: break; } |
列挙型はEnumerationを継承したオブジェクトであり、列挙子の実体はEnumeration#Valクラスなので、そのメソッドが呼び出せる。
Scala | Java相当 | 備考 | |
---|---|---|---|
列挙子の名前 |
e.toString() e.toString |
e.name() |
|
列挙子のID(序数) |
e.id |
e.ordinal() |
|
大小比較 |
e1.compareTo(e2) e1 compare e2 e1 < e2 e1 <= e2 e1 > e2 e1 >= e2 |
e1.compareTo(e2) |
IDによる比較。 |
列挙子取得(名前) |
E.withName("name") |
E.valueOf("name") |
見つからない場合はjava.util.NoSuchElementExceptionが発生する。 |
列挙子取得(ID) |
E.apply(n) E(n) |
見つからない場合はjava.util.NoSuchElementExceptionが発生する。 | |
列挙子一覧取得 |
E.values |
E.values() |
ID順に並んでいるようだ。 |
列挙子の最大ID |
E.maxId |
実際に使われているIDの最大値+1が返る。 |
列挙子の型(クラス)の実体はEnumeration内のValクラスとなる。[2011-01-09]
異なる列挙型を定義しても、それは変わらない。
しかし異なる列挙型の列挙子の型は区別され、お互いに代入することは出来ない。
scala> object E1 extends Enumeration { val e1 = Value(0) } defined module E1 scala> object E2 extends Enumeration { val e2 = Value(0) } defined module E2 scala> var e = E1.e1 e: E1.Value = e1 scala> e = E2.e2 <console>:19: error: type mismatch; found : E2.Value required: E1.Value e = E2.e2 ^ scala> E1.e1 == E2.e2 res2: Boolean = false scala> E1.e1 < E2.e2 <console>:19: error: could not find implicit value for parameter ord: scala.math.Ordering[Enumeration#Value] E1.e1 < E2.e2 ^
Scalaの内部クラス(Enumerationで言えばValクラス)がパス依存なので区別されるらしい。
参考: 花井 志生さん(るいもの戯れ言)のScalaのenum
と、いう事は、キャストしてやれば同じものとして扱える…。
scala> var e: Enumeration#Value = E1.e1 e: Enumeration#Value = e1 scala> e = E2.e2 e: Enumeration#Value = e2
個別の列挙子からその列挙型を取得して、列挙子一覧を取得する方法を考えてみる。[2011-04-15]
列挙子のクラスの実体であるEnumeration#ValueやEnumeration#Valには、列挙型を取得するメソッドは公開されていない。
しかしouterEnumというprivate valがあるので、リフレクションを使えば無理矢理だが取れそう。
object EnumSample extends Enumeration { val E1, E2, E3 = Value }
scala> EnumSample.E1.getClass.getDeclaredFields.foreach { println } public static final long scala.Enumeration$Val.serialVersionUID public final int scala.Enumeration$Val.scala$Enumeration$Val$$i private final java.lang.String scala.Enumeration$Val.name scala> EnumSample.E1.getClass.getDeclaredMethods.foreach { println } public scala.Enumeration scala.Enumeration$Val.scala$Enumeration$Val$$$outer() public java.lang.String scala.Enumeration$Val.toString() public java.lang.Object scala.Enumeration$Val.readResolve() public int scala.Enumeration$Val.id() scala> EnumSample.E1.getClass.getSuperclass.getDeclaredFields.foreach { println } public static final long scala.Enumeration$Value.serialVersionUID private final scala.Enumeration scala.Enumeration$Value.scala$Enumeration$$outerEnum public final scala.Enumeration scala.Enumeration$Value.$outer scala> EnumSample.E1.getClass.getSuperclass.getDeclaredMethods.foreach { println } public boolean scala.Enumeration$Value.$less(java.lang.Object) public boolean scala.Enumeration$Value.$greater(java.lang.Object) public boolean scala.Enumeration$Value.$less$eq(java.lang.Object) public boolean scala.Enumeration$Value.$greater$eq(java.lang.Object) public scala.Enumeration scala.Enumeration$Value.scala$Enumeration$$outerEnum() public int scala.Enumeration$Value.mask32() public long scala.Enumeration$Value.mask64() public scala.Enumeration scala.Enumeration$Value.scala$Enumeration$Value$$$outer() public boolean scala.Enumeration$Value.equals(java.lang.Object) public int scala.Enumeration$Value.hashCode() public int scala.Enumeration$Value.compareTo(java.lang.Object) public int scala.Enumeration$Value.compare(java.lang.Object) public int scala.Enumeration$Value.compare(scala.Enumeration$Value) public abstract int scala.Enumeration$Value.id()
どうやら実体であるValの親クラスValueのプライベートフィールド「scala$Enumeration$$outerEnum」がそれらしい。
また、このゲッターメソッドがなぜかpublicで存在しているので、これを呼び出せそう。
(outerEnumの可視性はprivate[Enumeration]なので、特定のクラスからは呼び出せる必要がある。その為、コンパイルされた実体としてはpublicにならざるを得ないのだろう)
scala> val e = EnumSample.E1.getClass.getMethod("scala$Enumeration$$outerEnum").invoke(EnumSample.E1).asInstanceOf[Enumeration] e: Enumeration = EnumSample scala> e.values res6: e.ValueSet = EnumSample.ValueSet(E1, E2, E3)