2015-05-24 84 views
4

我找到怎樣的一個古怪的在下面的斯卡拉程序(抱歉,包括所有的代碼,但你會明白爲什麼我說這一切):斯卡拉未能初始化VAL

object md2html extends App { 
    private val DEFAULT_THEME = Themes.AMAZON_LIGHT 

    private val VALID_OPTIONS = Set("editorTheme", "logo", "style") 
    try { 
     // some code 1 
    } catch { 
     case t: Throwable => t.printStackTrace(); exitWithError(t.getMessage) 
    } 

    // some code 2 (method definitions only) 

    private def parseOption(key: String, value: String) = { 
     println(key + " " + VALID_OPTIONS) 
     if (! Set("theme","editorTheme", "logo", "style").contains(key)) exitWithError(s"$key is not a valid option") 
     if (key == "theme") Themes(value).toMap else Map(key.drop(2) -> value) 
    } 

    // some code 3 (method definitions only) 
} 

如果VALID_OPTIONSsome code...之後定義,則在parseOption中評估爲空。我看不出有什麼好的理由。爲了清楚起見,我截斷了代碼,但是如果需要更多代碼,我會很樂意添加它。

編輯:我看了更多一點,這是我發現的。

當延長App,該val是不是跟這個代碼

object Test extends App { 
    printTest() 
    def printTest = println(test) 
    val test = "test" 
} 

與常規主要方法初始化,它工作正常:

object Test { 
    def main(args: Array[String]): Unit = { 
     printTest 
    } 
    def printTest = println(test) 
    val test = "test" 
} 
+0

[Scala - vals的初始化順序]的可能重複(http://stackoverflow.com/questions/14568049/scala-initialization-order-of-vals) – Suma

+0

如果您正在尋找比Suma更具體的原因和0 __「必須是初始化順序」,您需要發佈一個足夠詳細的簡單示例,以便能夠運行以重現問題。 –

+0

這不是一個重複的,因爲我有一個額外的因素:我延長'應用程序' – Dici

回答

10

我曾監督你使用extends App。這是Scala的另一個陷阱,遺憾的是:

object Foo extends App { 
    val bar = "bar" 
} 

Foo.bar   // null! 
Foo.main(Array()) 
Foo.bar   // now initialized 

App特質推遲對象的初始化爲main方法的調用,所以所有的val s爲null直到main方法被調用。

綜上所述,App性狀和val性狀不好。我陷入了陷阱多次。如果使用App,則應避免使用val,如果必須使用全局狀態,請改用lazy val

+0

明白了,謝謝:) – Dici

1

構造體,這也適用於單一對象爲好吧,從上到下嚴格評估。不幸的是,在Scala中這是一個常見的陷阱,因爲如果在構造函數的其他地方引用了val s,它就會變得相關。

object Foo { 
    val rab = useBar // oops, involuntarily referring to uninitialized val 
    val bar = "bar" 

    def useBar: String = bar.reverse   
} 

Foo // NPE 

當然,在一個更美好的世界,Scala編譯器要麼不允許上面的代碼,重新排序的初始化,或至少向您發出警告。但它不...

+0

好吧,'一些代碼2'高於'val'的第一個用法,那麼爲什麼當我在註釋中聲明它時仍然評估爲空? – Dici

+0

如果當您將'val'更改爲'lazy val'時,NPE消失了,我保證您的問題是初始化的順序,並且它可能根本不會在第一眼看到。 –

+0

這肯定與我擴展'App'的事實有關。它與初始化的順序有關,當然,但它不會發生與常規的主要方法(測試) – Dici