2009-09-08 18 views
16

En Scala Puedo hacer esto:Scala sin obedecer la definición no abstracta con una var

trait SomeTrait { 
    protected def foo: String 
} 

class Wibble extends SomeTrait { 
    protected var foo = "Hello" 
} 

pero no puedo hacer lo mismo en el que proporcionar una definición por defecto para foo

trait SomeTrait { 
    protected def foo: String = "World" 
} 

class Wibble extends SomeTrait { 
    protected var foo = "Hello" //complains about lack of override modifier 

    override protected var foo = "Hello" //complains "method foo_ overrides nothing" 
} 

Por qué no puedo hacer esto?

EDIT: Después de la lista de una conversación en el Scala-usuarios de correo, tengo raised this in trac

Respuesta

19

En Scala, cuando se escribe un var foo, el compilador Scala genera automáticamente un colocador (llamado foo_=) y un captador (llamado foo) para él, y establece el campo como privado (lo verá como privado si descompila una clase que tiene campos Scala 'públicos' con javap). Eso es lo que significa el error "método foo_ = anula nada". En su rasgo no ha definido un método foo_=, y para un setter de campo público y captadores siempre vienen en pares.

Si no proporciona un valor predeterminado en el rasgo (es decir, el método abstracto), la palabra clave override no es necesaria. Por lo tanto, en su primer ejemplo, el getter anula el método abstracto y el setter ... simplemente está allí. El compilador no se queja. Pero cuando proporciona una implementación real del método en el rasgo, debe escribir específicamente la palabra clave override al anular. Al escribir protected var foo, no ha especificado la palabra clave override para el captador y al escribir override protected var foo, también ha indicado al compilador que el método foo_= debe anularse, pero el rasgo no tiene dicho método.

Además, lógicamente no se puede anular realmente un def con un (teniendo en cuenta una visión estricta de anulación, como en el párrafo anterior). A def es lógicamente una función (le da algo de entrada, produce una salida). Un var es similar a una función no-arg, pero también admite establecer su valor en otra cosa, una operación que no es compatible con una función. En cambio, si lo cambiara a val, estaría bien. Es como una función que siempre produce el mismo resultado (en caché).

Si usted quiere tener un comportamiento similar a un var se podría hacer algo como esto (por tener colocador explícita y getters):

class Wibble extends SomeTrait { 
    private var bar = "Hello" 
    override protected def foo = bar 
    protected def foo_=(v: String) { bar = v} 
} 

Ahora se puede hacer cualquier cosa que podría hacer con un :) var.

val x = new Wibble 
println(x.foo) // yields "Hello" 
x.foo = "Hello again" 
println(x.foo) // yields "Hello again" 
+0

Lo siento, he cometido un error: el método de rasgo original también debería haber sido protegido. No estoy seguro de estar de acuerdo contigo acerca de que lógicamente no se puede anular una 'definición' con una 'var'. Todo lo que mi 'def' dice es que espero que haya un acceso llamado' foo' que devuelve un String - declarar que 'var' es una implementación de este –

+0

Creo que estoy de acuerdo contigo. Estaba pensando en anularlo como una noción más estricta cuando escribí la respuesta. Editaré la respuesta y proporcionaré una solución viable :). –

+0

Es una lástima que no haya una sintaxis 'anular def como var' –

Cuestiones relacionadas