2009-11-17 10 views
7

Estoy con ganas de hacer algo como esto:Cómo subclase un objeto con una var en su constructor principal

class A (var updateCount: Int) { 
} 

class B (val name: String, var updateCount: Int) extends A(updateCount) { 
    def inc(): Unit = { 
    updateCount = updateCount + 1 
    } 
} 

var b = new B("a", 10) 
println(b.name) 
println(b.updateCount) 

b.updateCount = 9999 
b.inc 
println(b.updateCount) 

pero el compilador no le gusta.

(fragment of extend.scala):5: error: error overriding variable updateCount in class A of type Int; 
variable updateCount needs `override' modifier 
class B (val name: String, var updateCount: Int) extends A(updateCount) { 

Añadiendo la anulación en updateCount tampoco funciona. ¿Cuál es la manera limpia de hacer esto?

+0

Un par de personas han señalado que debo eliminar la var de updateCount en B. Esto no funciona. Si lo intenta, debe obtener (fragmento de extend.scala): 7: error: reasignación a val updateCount = updateCount + 1 que sale del método inc. – Trenton

Respuesta

7

No es necesario declarar la var en la firma constructor de la subclase:

class B (val name: String, /* note no var */ updateCount: Int) extends A(updateCount) { 
    //... 
} 

Esto también se extiende a las clases con val s en sus constructores también: la

scala> class C(val i: Int) 
defined class C 

scala> class D(j: Int) extends C(j) 
defined class D 
+0

Esto no funciona. Si utilizo el ejemplo exacto I, siempre, la eliminación de la var de UpdateCount, consigo (fragmento de extend.scala): 7: error: reasignación a val UpdateCount = UpdateCount + 1 que sale del método inc. – Trenton

+0

Simplemente tendrá que cambiar el nombre de los parámetros en la clase B: use 'updateCountIn' en la firma del constructor y llame al constructor de la clase A; aún podrá acceder a 'updateCount' en el constructor/cuerpo de la clase B. – bbarker

4

Es necesario evitar teniendo el identificador declarado para B sombreando el identificador declarado para A. La forma más fácil de hacerlo es elegir un nombre diferente. Sin embargo, si usted realmente, realmente no quiere hacer eso, aquí es una alternativa:

class B (val name: String, updateCount: Int) extends A(updateCount) { 
    self: A => 
    def inc(): Unit = { 
    self.updateCount = self.updateCount + 1 
    } 
} 

Y, dicho sea de paso, deje caer el var de la declaración B.

+1

Guau, eso es bastante trabajo.Esto parece una extraña limitación del lenguaje. Si tuviera un gráfico de herencia de 5 de profundidad, ¿tendría que seguir apareciendo nombres "falsos" para estos argumentos? updateCountDontUse1, y en su subclase updateCountDontUse2, etc. No es solo el nombre ... es el cruft, también. Es un campo extra que está sentado en mi clase, rogándole a alguien que lo use y obtenga malos resultados. – Trenton

+2

Esa es la cuestión ... los parámetros de la clase no son realmente campos, a menos que se haya precedido con 'val' o' var'. Si no los utiliza en ninguna otra parte que no sea el constructor, no se almacenarán como campos en la clase. –

2

Cuando utiliza la palabra clave var en los parámetros, esto hace que el valor pasado sea un nuevo var en la clase. Cuando no lo hace, lo convierte en un parámetro de constructor (únicamente) y usa su valor para el var pasándolo al constructor. Entonces el ejemplo que la gente ha dado

class B(val name:String, updateCount:Int) extends A(updateCount) 

es correcto.

Sin embargo, scala hace que los parámetros del constructor estén directamente disponibles para los métodos de la clase (no estoy seguro por qué), así que si usa el mismo nombre, su código no compilará con el error reassignment to val cuando intente reasignar la "var". Por ejemplo, en el siguiente fragmento de código, el parámetro del constructor inmutable sombrea el var heredado y, por lo tanto, no se puede asignar al parámetro.

class B (val name: String, updateCount: Int) extends A(updateCount) { 
    def inc(): Unit = { 
    updateCount = updateCount + 1 
    } 
} 
+0

clase B (nombre val: String, updateCount: Int) extends A (updateCount) no compilará para mí. Obtengo (fragmento de extend.scala): 7: error: reasignación a val updateCount = updateCount + 1 – Trenton

+0

La primera versión se compila. La segunda versión intencionalmente no, y demuestra el problema con el uso del mismo nombre para la var y el parámetro constructor. –

0

Como otros mencionan, su parámetro de constructor en B está sombreando la versión de la superclase. Aquí está el código que funciona y no requiere auto-tipo:

class A (var updateCount: Int) { 
} 

class B (val name: String, uc: Int) extends A(uc) { 
    def inc(): Unit = { 
    updateCount = updateCount + 1 
    } 
} 
Cuestiones relacionadas