2013-04-02 8 views
7

se scrivo:Come inizializzare il valore da tratto nel sottotipo?

trait T { 
    val t = 3 
    val u = 1::t::Nil 
} 

class U extends T { 
    override val t = 2 
} 

(new U).u 

lo dimostra questo.

List(1, 0) 

Come dovrei cambiare il codice di cui sopra per farla visualizzare il seguente:

List(1, 2) 

cioè override val t imposta il valore di t per u nel tratto T?

+1

è possibile definire u come 'lazy val' –

risposta

12

Un modo per fare questo è quello di ritardare la valutazione di u utilizzando def o lazy val come segue:

trait T { 
    def t = 3 
    def u = 1::t::Nil 
} 

class U extends T { 
    override def t = 2 
} 

(new U).u 

o

trait T { 
    val t = 3 
    lazy val u = 1::t::Nil 
} 

class U extends T { 
    override val t = 2 
} 

(new U).u 

Le differenze sono le seguenti:

  • val rende un'espressione valutata durante l'inizializzazione
  • def fa un'espressione valutare ogni volta che viene utilizzato u
  • lazy val rende valutato in prima u utilizzo e memorizza nella cache il risultato
10

Prova ad utilizzare un inizializzatore precoce:

scala> trait T { 
    | val t = 3 
    | val u = 1::t::Nil 
    | } 
defined trait T 

scala> class U extends { 
    | override val t = 2; 
    | } with T 
defined class U 

scala> (new U).u 
res1: List[Int] = List(1, 2) 

Vedi esempio here per ulteriori informazioni sull'inizializzazione anticipata.

+0

Sebbene corretto, per motivi di leggibilità, preferisco utilizzare il metodo cache con lazy vals. Se ho bisogno di aggiungere codice alla mia classe U, non posso metterlo tra parentesi, ho bisogno di creare un altro gruppo, come la classe U estende {override val t = 2} con T {... il mio codice qui ... } –

+0

Il problema con questo approccio è che ogni accesso è sincronizzato per assicurarsi che il 'lazy val' sia effettivamente pronto. Rallenta l'applicazione e non deve essere utilizzata alla cieca su percorsi critici. –

4

Tutto lo scala stile dichiarativo è solo un'illusione. Scala è costruito su una jvm e funziona come java.

Evetything è una classe e deve essere indipendente dal suo utilizzo (java non è C++ e supporta la build incrementale con i suoi pro e contro). Ogni tratto ha il proprio codice di inizializzazione e la classe multi-traccia esegue il rispettivo codice di inizializzazione uno per uno. Se si utilizza un AnyRef dichiarato solo in una sottoclasse di quella il suo valore verrà impostato per null durante l'inizializzazione.

Mi guardo con regole di convenzione specifiche: ogni valore deve essere finale o pigro (why using plain val in non-final classes). Quindi non mi interessa l'ordine di inizializzazione e posso fingere che sto usando un linguaggio dichiarativo.

Inoltre sto usando l'opzione -Xcheckinit: aggiungi il controllo di runtime agli accessori di campo.

Problemi correlati