LoginSignup
5
4

More than 5 years have passed since last update.

Scalaの列挙型をJavaから参照してみる

Posted at

Javaには列挙型のクラスを作成するenumがあり、実際にはコンパイル時に色々自動生成しているらしい。
Scalaにはそれとは別のEnumerationクラスがあり(むしろ enum はキーワードとして予約されていない)、これを継承したシングルトンオブジェクトが列挙するインスタンスのグループを表す。

以下サンプル。

Signal.scala
/**
 * Define Signal Enumeration
 */
object Signal extends Enumeration {

  val Green  = Value        //=> Val(0, "Green")
  val Yellow = Value(2)     //=> Val(2, "Yellow")
  val Red    = Value("RED") //=> Val(3, "RED")

  // Alias for Java
  def valueOf(name: String) = withName(name)

  // Java-like methods addition (can't use implicitly from Java)
  implicit class JavaLikeValue(v: Value) {
    def name = v.toString
    def ordinal = v.id
  }
}

使用するときは以下のようにする。
implicit class があると、いかにも列挙型の値にメソッドを追加したように見える。

ScalaMain.scala
/**
 * Use Signal
 */
object ScalaMain extends App {

  // Iteration
  Signal.values.foreach { signal =>
    println(s"id: ${signal.id}, toString: ${signal}")
  }

  // Get singleton instance
  val g = Signal.Green
  val y = Signal(2)              // by id
  val r = Signal.withName("RED") // by name

  // Mapping function
  def toMessage = {
    import Signal._ // import for shortcut

    // pattern match (like switch-case in Java)
    (_: Value) match {
       case Green  => "Go ahead"
       case Yellow => "Be careful"
       case Red    => "Stop"
    }
  }
  println( toMessage(r) )

  // implicit conversion
  println( g.name )
  println( y.ordinal )
}

一方これをJavaから参照して使う場合は以下のようになる。

Main.java
public class Main {
  public static void main(String[] args) {
    // Signal class
    System.out.println(Signal.class.toString());

    // Signal$ class (Signal.type @ Scala)
    System.out.println(Signal$.class.toString());

    // Signal singleton object
    Signal$ obj = Signal$.MODULE$;
    System.out.println(obj.toString());

    // Get enumeration instance
    System.out.println(Signal.Green().toString());
    System.out.println(Signal.apply(2).toString());
    System.out.println(Signal.withName("RED").toString());
    System.out.println(Signal.valueOf("RED").toString());

    // Instance Type (Inner class of singleton object class)
    Signal$.Value a = Signal.Yellow();
    System.out.println(a.id());

    // Use methods explicitly
    System.out.println(new Signal.JavaLikeValue(Signal.Green()).name());
  }
}

JavaからScalaコードを参照する場合は、以下に気をつける。

  • object Signal の型は、Signal$ として参照できる。
  • 列挙子(インスタンス)の型は Signal$.Value (内部クラス)となる。
  • 暗黙の変換(implicit conversion)は明示的に呼び出す。(Scalaコンパイラの実行時に処理するため)
  • Javaのswitch-case文では利用できない(?)

ちなみに、Scalaでは type Signal = Signal.Value とすることで型エイリアスを宣言できるが、これもコンパイラが解決してくれるだけなので、出来上がったクラスを javap でチェックしても、型エイリアスの情報は消えている。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4