2015-03-27 9 views
6

In Scala 2.10.4, Data la seguente classe:Risultato imprevisto quando prevalente 'val'

scala> class Foo { 
    | val x = true 
    | val f = if (x) 100 else 200 
    | } 
defined class Foo 

I seguenti due esempi senso per me:

scala> new Foo {}.f 
res0: Int = 100 

scala> new Foo { override val x = false}.f 
res1: Int = 200 

Ma, perché non lo fa questa chiamata restituisce 100?

scala> new Foo { override val x = true }.f 
res2: Int = 200 
+1

Dude, http://docs.scala-lang.org/tutorials/FAQ/initialization-order.html –

risposta

11

Perché vals non vengono inizializzati più di una volta, è in realtà xnull (o false per un default Boolean) durante l'inizializzazione di Foo, e poi inizializzata nella classe anonima che sta estendendo Foo nel tuo esempio.

Siamo in grado di testare più facilmente con un AnyRef:

class Foo { 
    val x = "" 
    val f = if (x == null) "x is null" else "not null" 
} 

scala> new Foo { override val x = "a" }.f 
res10: String = x is null 

scala> new Foo {}.f 
res11: String = not null 

C'è una spiegazione completa nel Scala FAQ. Estratto:

Naturalmente quando una val è ignorata, non viene inizializzata più di una volta. Quindi, anche se x2 nell'esempio precedente è apparentemente definita in ogni punto, questo non è il caso: una val override sembrerà essere nullo durante la costruzione di superclassi, così come una val astratta.

Un modo semplice per evitare ciò sarebbe utilizzare un valore lazy val o def, se la valzione a cui si fa riferimento può essere sovrascritta.

Inoltre, è possibile utilizzare il flag -Xcheckinit compilatore mettere in guardia su possibili errori di inizializzazione come questo.

+0

Quindi, non è possibile eseguire l'override di ** a 'val', quindi? Nell'esempio sopra, 'x' è * null *, piuttosto che impostato su" "a" '. Mi fa chiedere perché un 'val' dovrebbe anche essere sopraffatto - dato il comportamento sopra? –

+0

@KevinMeredith Si può sovrascrivere una val, è solo che bisogna stare molto attenti a problemi di inizializzazione quando si esegue. Vale a dire, quando si esegue l'override di una val che dipende da un'altra val della super-classe. Nel contesto del tuo problema, non può essere sovrascritto e funziona ancora correttamente senza fare qualcosa di pigro. –

+0

Sì, se si cambia 'f' di essere un' def' o 'lazy', allora sarà chiamato dopo l'inizializzazione e il lavoro. –

Problemi correlati