更新- 2014/09/17
以前の更新 (2013 年 2 月 19 日から) のソリューションでprintln(Value.Player2)
さえ、最初のコマンドとして配置すると機能しないことが判明しました。つまり、序数はまだ正しく割り当てられていません。
それ以来、検証可能な実用的なソリューションを Gist として作成しました。実装は、すべての JVM クラス/オブジェクトの初期化が完了するまで、序数の割り当てを待機します。また、(逆) シリアル化に対して非常に効率的でありながら、追加のデータを使用して各列挙型メンバーを拡張/装飾することも容易になります。
また、Scala で使用されているすべての異なる列挙パターンについて詳しく説明するStackOverflow の回答も作成しました(上記の Gist のソリューションを含む)。
TypeSafe IDE (ScalaIDE がプリインストールされた Eclipse)の新規インストールで作業しています。私はWindows 7-64ビットを使用しています。そして、私は Scala Worksheet でさまざまな成功を収めました。1 時間以内に 3 回、マシンがハード クラッシュしました (フル リセットまたはブルー スクリーンに 1 回)。したがって、これは Scala Worksheet のバグである可能性があります。私はまだ確信が持てず、その問題を追跡する時間がありません. ただし、この列挙の問題により、テストが妨げられています。
Scala ワークシートで次のコードを使用しています。
package test
import com.stack_overflow.Enum
object WsTempA {
object Value extends Enum {
sealed abstract class Val extends EnumVal
case object Empty extends Val; Empty()
case object Player1 extends Val; Player1()
case object Player2 extends Val; Player2()
}
println(Value.values)
println(Value.Empty)
}
上記は正常に動作します。ただし、最初の println をコメントアウトすると、2 行目で java.lang.ExceptionInInitializerError という例外がスローされます。そして、私はScalaの初心者で、なぜそれが起こっているのか理解できません. どんな助けでも大歓迎です。
Scala ワークシートの右側からのスタック トレースを次に示します (左側は、ここで適切に表示するために削除されています)。
java.lang.ExceptionInInitializerError
at test.WsTempA$Value$Val.<init>(test.WsTempA.scala:7)
at test.WsTempA$Value$Empty$.<init>(test.WsTempA.scala:8)
at test.WsTempA$Value$Empty$.<clinit>(test.WsTempA.scala)
at test.WsTempA$$anonfun$main$1.apply$mcV$sp(test.WsTempA.scala:14)
at org.scalaide.worksheet.runtime.library.WorksheetSupport$$anonfun$$exe
cute$1.apply$mcV$sp(WorksheetSupport.scala:76)
at org.scalaide.worksheet.runtime.library.WorksheetSupport$.redirected(W
orksheetSupport.scala:65)
at org.scalaide.worksheet.runtime.library.WorksheetSupport$.$execute(Wor
ksheetSupport.scala:75)
at test.WsTempA$.main(test.WsTempA.scala:11)
at test.WsTempA.main(test.WsTempA.scala)
Caused by: java.lang.NullPointerException
at test.WsTempA$Value$.<init>(test.WsTempA.scala:8)
at test.WsTempA$Value$.<clinit>(test.WsTempA.scala)
... 9 more
クラス com.stack_overflow.Enum は、この StackOverflow スレッドから取得されます。簡単にするために、ここに自分のバージョンを貼り付けました(コピー/貼り付け操作中に重要なものを見逃した場合に備えて):
package com.stack_overflow
//Copied from https://stackoverflow.com/a/8620085/501113
abstract class Enum {
type Val <: EnumVal
protected var nextId: Int = 0
private var values_ = List[Val]()
private var valuesById_ = Map[Int ,Val]()
private var valuesByName_ = Map[String,Val]()
def values = values_
def valuesById = valuesById_
def valuesByName = valuesByName_
def apply( id : Int ) = valuesById .get(id ) // Some|None
def apply( name: String ) = valuesByName.get(name) // Some|None
// Base class for enum values; it registers the value with the Enum.
protected abstract class EnumVal extends Ordered[Val] {
val theVal = this.asInstanceOf[Val] // only extend EnumVal to Val
val id = nextId
def bumpId { nextId += 1 }
def compare( that:Val ) = this.id - that.id
def apply() {
if ( valuesById_.get(id) != None )
throw new Exception( "cannot init " + this + " enum value twice" )
bumpId
values_ ++= List(theVal)
valuesById_ += ( id -> theVal )
valuesByName_ += ( toString -> theVal )
}
}
}
あらゆる種類のガイダンスをいただければ幸いです。
更新- 2013 年 2 月 19 日
Rex Kerr との数サイクルの後、現在動作するコードの更新バージョンを次に示します。
package test
import com.stack_overflow.Enum
object WsTempA {
object Value extends Enum {
sealed abstract class Val extends EnumVal
case object Empty extends Val {Empty.init} // <---changed from ...Val; Empty()
case object Player1 extends Val {Player1.init} // <---changed from ...Val; Player1()
case object Player2 extends Val {Player2.init} // <---changed from ...Val; Player2()
private val init: List[Value.Val] = List(Empty, Player1, Player2) // <---added
}
println(Value.values)
println(Value.Empty)
println(Value.values)
println(Value.Player1)
println(Value.values)
println(Value.Player2)
println(Value.values)
package com.stack_overflow
//Copied from https://stackoverflow.com/a/8620085/501113
abstract class Enum {
type Val <: EnumVal
protected var nextId: Int = 0
private var values_ = List[Val]()
private var valuesById_ = Map[Int ,Val]()
private var valuesByName_ = Map[String,Val]()
def values = values_
def valuesById = valuesById_
def valuesByName = valuesByName_
def apply( id : Int ) = valuesById .get(id ) // Some|None
def apply( name: String ) = valuesByName.get(name) // Some|None
// Base class for enum values; it registers the value with the Enum.
protected abstract class EnumVal extends Ordered[Val] {
val theVal = this.asInstanceOf[Val] // only extend EnumVal to Val
val id = nextId
def bumpId { nextId += 1 }
def compare(that: Val ) = this.id - that.id
def init() { // <--------------------------changed name from apply
if ( valuesById_.get(id) != None )
throw new Exception( "cannot init " + this + " enum value twice" )
bumpId
values_ ++= List(theVal)
valuesById_ += ( id -> theVal )
valuesByName_ += ( toString -> theVal )
}
}
}