Scalaのenumは直列化できない?
Valueがインナークラスだというのが、かなりつらいな。Value自体は直列化可能じゃないから、デフォルトコンストラクタが必要だけど、Valueはインナークラスだから、エンクロージングクラスを引数とした、コンストラクタしか用意されていない。う〜む、とりあえずenumは、Javaで用意かなぁ。
Scalaのenum
Scalaでは、enumはどうするんだろうと思っていたんだけど、ちゃんとscala.Enumerationというクラスが用意されていた。いや名前から、java.util.Enumerationみたいなもんだと思って見落としていたんだけど。Scalaなんだから、そんな後方互換性は不要だよな。
Enumerationは、Valueというインナクラスで、メンバを表現する。つまりenum自体と、その中に定義される定数とは、別のクラスになっている。
object Const extends Enumeration {
def ONE, TWO = Value
}
みたいにして使う。このValueは、インナクラスのValueなのではなくて、Enumeration内に定義されたメソッドだ。
protected final def Value: Value =
new Val(nextId, if (nextName.hasNext) nextName.next else null)
で、戻り型は、インナクラスのValueだ。あぁややこしい。で、このValueクラスを見てみると、
abstract class Value extends Ordered[Value] {
/** the id and bit location of this enumeration value */
def id: Int
override def compare(that: Value): Int = this.id - that.id
override def equals(other : Any) : Boolean =
other match { case that : Value => compare(that) == 0
case _ => false }
override def hashCode : Int = id.hashCode
...
idが一致すればokなのか。ってそれじゃ、無関係のenum同士がequalになってしまうのでは?
object Const1 extends Enumeration {
val ONE, TWO = Value
}
object Const2 extends Enumeration {
val ONE, TWO = Value
}
object Main {
def main(args: Array[String]) {
System.out.println(Const1.ONE == Const2.ONE)
}
}
shanai@shanai-desktop:/tmp$ scala -cp . Main false
あれ? 平気だ。こんなコードを試しに作ってみると、
class Base {
class Value {
def c(v: Value) {}
}
}
class Foo1 extends Base {
val ONE = new Value
}
class Foo2 extends Base {
val ONE = new Value
}
object Main {
def main(args: Array[String]) {
val foo1 = new Foo1
val foo2 = new Foo2
System.out.println(foo1.ONE.c(foo2.ONE))
}
}
shanai@shanai-desktop:/tmp$ fsc test2.scala
/tmp/test2.scala:20: error: type mismatch;
found : foo2.Value
required: foo1.Value
System.out.println(foo1.ONE.c(foo2.ONE))
^
one error found
あぁ、これがパス依存型というやつか。ValueはBaseクラスにしかないけど、インスタンスによって、別のクラスだと認識されるんだね。このあたりは、Javaから来ると、かなり混乱するな。でもインナクラスのインスタンスってエンクロージングクラスのインスタンスを含んでるわけだから、むしろ、こっちの方が自然な気もしてきた。





