2016-09-19 13 views
3

スカラーの「手書き列挙」の初期化でバグが見つかりました。オブジェクトが内部にあるのはsealed case classobject SomeCodeなので手書きです。Scalaオブジェクト初期化のバグ

おもしろいことに、sealed case classにデフォルト値が設定されていると、多少の暗い魔法が発生します。我々はobject SomeCode開始の初期化SomeCode.Fistを呼び出すと

import com.blabla.SomeCode 
import org.scalatest.{Matchers, WordSpec} 

class SomeCodeTest extends WordSpec with Matchers { 
    "SomeCode" should { 
    "work properly" in { 
     println(SomeCode.First.toString) 
    } 
    } 
} 

sealed case class SomeCode(
    id: String, 
    legend: String) 

object SomeCode { 

    object First  extends SomeCode(id = "First", legend = "first legend") 
    object Second  extends SomeCode(id = "Second", legend = "second legend") 

    val values = Seq(
    SomeCode.First, 
    SomeCode.Second) 

    private val CACHE: Map[String, SomeCode] = { 
    val ids = values.map(_.id) 
    (ids zip values).toMap 
    } 

    def getById(id: String): Option[SomeCode] = CACHE.get(id) 
} 

そして、もう一つのテスト: は、たとえば、我々は次のようになり、 "手書きの列挙" を持っています。したがって、val valuesprivate val CACHEの初期化も実際にすべて正常に開始されます。我々はsealed case classためデフォルト値を導入した場合

しかし、...:

sealed case class SomeCode(
    id: String, 
    legend: String = "default legend") 
... 
object First  extends SomeCode(id = "First") 
object Second  extends SomeCode(id = "Second") 

、今我々のテストを実行します - 私たちはCACHEでNPEを持つことになります。

SomeCode.First - この値はnullとなり、valuesになるので、values.map(_.id)はNPEを投げます。 テストから、我々はSomeCode.Secondを呼び出します場合は、nullは、私はそれががsealed case class拡張良い習慣ではないことを知っているが、それにもかかわらず、それが正常に動作するはずSomeCode.Second

になります。たぶん私はスカラーで何かを理解していないかもしれませんが、現在は私にとってはコンパイラのバグのようです。

scalaVersion := "2.11.7"

また、私はScalaの-LANGで問題を作成します。私たちはSomeCode.First.toStringを呼び出すときに、SomeCode.First次のコードでnullとしてセットアップ済みですのでhttps://issues.scala-lang.org/browse/SI-9929

+0

興味深いことに、次のコードでREPLの出力を見て?なぜなら、与えられたコードでは、あなたが記述した振る舞いを再現することができないからです。言い換えれば: 'Works fine for me' –

+0

@SaschaKolbergは、デフォルト値である 'legend:String =" default legend ")でうまく動作し、拡張オブジェクトでこの値を設定しません。 – invis

+0

いいえ、そうではありません。 –

答えて

2

問題が起こっている:

val values = Seq(SomeCode.First, SomeCode.Second)

REPLに値の出力を印刷することで、上記を確認できます。それは何かがあなたのコード例に欠落していることだろう

sealed case class SomeCode(
    id: String, 
    legend: String = "default") 

object SomeCode { 
    println("begin object init") 
    object First extends SomeCode(id = "First"){println("initializing First")} 
    object Second extends SomeCode(id = "Second"){println("initializing Second")} 
    println(SomeCode.First) 
    println(SomeCode.Second) 
} 

SomeCode.First 

// REPL Output: 
begin object init 
null <--- SomeCode.First is null!!! Why does it not initialize the First object? 
initializing Second <--- Correctly initializes the Second object. 
SomeCode(Second,default) 
initializing First <--- Now starts to initialize the First object 
res41: SomeCode.First.type = SomeCode(First,default) 
+0

ありがとう、これは私の質問の本質です。興味深いことに、Firstを 'Object extends FirstCode(id =" First "、" notDefault ")'のように変更すると、すべてが問題なくなります。 OR '' SomeCode {'object SomeCodes {' – invis

+0

haha​​という名前にオブジェクトの名前を変更してください。私は正確な 'SomeCodes'バリエーションを試しました。しかし、何が起こっているのか分からない。 – Samar

関連する問題