2015-07-14 8 views
13

Perché non è possibile sovrascrivere la variabile mutabile in scala?Perché non è possibile sovrascrivere la variabile mutabile in scala?

class Abs(var name: String){ 
} 

class AbsImpl(override var name: String) extends Abs(name){ 
} 

Sopra codice dà seguente errore di tempo di compilazione: -

variable name cannot override a mutable variable

Se il nome è dichiarata val, quindi al di sopra codice funziona bene.

+0

Perché qualcuno dovrebbe voler "scavalcare" un 'var'? Qual è il significato di sovrascrivere una var? –

+0

Perché ignorare non ha molto senso. È mutabile, puoi solo cambiarlo.Cosa significa sovrascrivere? http://stackoverflow.com/questions/16413986/how-to-override-a-mutable-variable-in-trait-in-scala – Falmarri

+0

@Sarvesh: Grazie per la tua rapida risposta. Sto solo cercando di capire, perché è permesso per val? – mogli

risposta

4

Se è possibile eseguire l'override di una var con una var, il membro che esegue l'override potrebbe avere un tipo più ristretto. (Ecco come viene definito l'override.)

Si può quindi assegnare un valore di un tipo più ampio e quindi leggerlo aspettandosi il tipo più stretto e fallire.

Illustrazione del setter coinvolti:

scala> class A ; class B extends A 
defined class A 
defined class B 

scala> abstract class C { var x: A } ; class D extends C { var x: B = _ } 
<console>:13: error: class D needs to be abstract, since variable x in class C of type A is not defined 
(Note that an abstract var requires a setter in addition to the getter) 
     abstract class C { var x: A } ; class D extends C { var x: B = _ } 
              ^

scala> abstract class C { var x: A } 
defined class C 

scala> class D extends C { var x: B = _ ; def x_=(a: A) = ??? } 
defined class D 
+0

Quando si esegue l'override, non è che si possa avere un "tipo più ristretto". In realtà, ha la precedenza su due metodi, il getter e il setter. Il primo è covariante nel tipo var, il secondo è controvariante nel tipo var, quindi anche se si dovesse eseguire l'override, il tipo sarebbe invariante. –

+0

@ MikaëlMayer Questo è un altro modo per dire quello che ho dimostrato, tranne che la definizione di membro che ha la precedenza inizia con la conformità e non con il desugaring. http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#overriding –

+0

L'interpretazione di vars come getter e setter è l'unica supportata dalle specifiche . La relazione di conformità non tratta le variabili, solo i metodi e i vals, ma le variabili sono definite come "equivalenti" a un getter e setter. http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#variable-declarations-and-definitions. Direi che dovrebbe essere permesso. Invece è vietato anche se si tenta di scavalcare tramite un getter e un setter. Il mistero continua. –

0

Questo accade quando il var si sta cercando di sostituire già ha un incarico. Non sono sicuro che sia perché è vietato lo, ma ha anche poco senso.

Vedere anche this question.

Definire name come astratto invece

trait Abs { 
    var name: String 
} 

class AbsImpl(name0: String) extends Abs { 
    var name = name0 
} 

o

trait Abs { 
    var name: String 
} 

class AbsImpl(private var name0: String) extends Abs { 
    def name = { 
    println("getter") 
    name0 
    } 

    def name_=(value: String) = { 
    println("setter") 
    name0 = value 
    } 
} 
1

Credo che l'intento era semplicemente quello di impostare il valore della ereditato var name. Ciò può essere ottenuto in questo modo (senza override var):

class Abs(var name: String){ 
} 

class AbsImpl(name: String) extends Abs(name){ 
} 

L'ambiguità nasce dalla var locale name: String in AbsImpl che prende il nome ereditato da var name: StringAbs. Un codice simile, meno sintatticamente ambigue, ma anche meno elegante sarebbe:

class Abs(var name: String){ 
} 

class AbsImpl(name_value: String) extends Abs(name_value){ 
} 
2

La risposta breve: è necessario passare -Yoverride-vars al compilatore Scala.

Secondo le specifiche, un var è sia un getter che un setter e per questi metodi valgono le normali regole di override. Tuttavia, questo ha avuto alcune conseguenze indesiderate. alla parola chiave final e inlining. Il codice nel compilatore menziona sarebbero necessari alcuni chiarimenti spec:

// TODO: this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here. 
if (!settings.overrideVars) 
    overrideError("cannot override a mutable variable") 

Un biglietto correlato: SI-3770

+0

Non ero sicuro di 'classe C {def c = 42; def c _ = (x: Int): Unit =()}; (nuova C): {var c: Int} 'funzionerebbe. Qualcuno è stato recentemente sorpreso da 'class C {val c = 42}; (nuova C) .c _'. Forse le specifiche dovrebbero unificarle esplicitamente. Vedo che non posso 'class C {var c: Any = _}; la classe D estende C {override var c: Int = 42; def c _ = (x: Any) = c _ = (x.toString.toInt)} 'almeno non durante la mia pausa pranzo. –

0

Quando si desidera l'override un var suo equivalente a cercare di ignorare un campo in Java che non è possibile .