2009-09-08 4 views
16

In Scala kann ich dies tun:zwingende Scala eine nicht-abstrakte def mit einem var

trait SomeTrait { 
    protected def foo: String 
} 

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

Aber ich kann die gleiche Sache nicht tun, wo ich eine Standard-Definition sorgen für 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" 
} 

Warum kann ich das nicht tun?

EDIT: Nach einem Gespräch auf dem scala-users Mailingliste, ich habe raised this in trac

Antwort

19

In Scala, wenn Sie ein var foo schreiben, der Scala-Compiler generiert automatisch einen Setter (genannt foo_=) und einen Getter (genannt foo) dafür, und legt das Feld als private fest (Sie sehen es als private, wenn Sie eine Klasse mit 'öffentlichen' Scala-Feldern mit javap dekompilieren). Das ist, was die Methode foo_ = nichts außer Kraft setzt. In Ihrem Merkmal haben Sie keine foo_= Methode definiert, und für einen öffentlichen Feld Setter und Getters immer kommen paarweise.

Wenn Sie im Merkmal keinen Standardwert angeben (z. B. abstrakte Methode), ist das Schlüsselwort override nicht erforderlich. Daher überschreibt der Getter im ersten Beispiel die abstrakte Methode und den Setter ... es ist einfach da. Der Compiler beklagt sich nicht. Wenn Sie jedoch eine tatsächliche Implementierung der Methode im Merkmal bereitstellen, müssen Sie beim Überschreiben speziell das Schlüsselwort override schreiben. Wenn Sie protected var foo schreiben, haben Sie das Schlüsselwort override für den Getter nicht angegeben und beim Schreiben von override protected var foo haben Sie dem Compiler auch angezeigt, dass die Methode foo_= überschrieben werden soll, aber das Merkmal hat keine solche Methode.

Auch logisch können Sie nicht wirklich überschreiben def mit einer var (unter Berücksichtigung einer strengen Sicht des Übersteuerns, wie im vorherigen Absatz). Eine def ist logisch eine Funktion (Sie geben es eine Eingabe, es erzeugt eine Ausgabe). A var ähnelt einer "no-arg" -Funktion, unterstützt aber auch die Einstellung des Werts auf eine andere Funktion, die von einer Funktion nicht unterstützt wird. Wenn Sie es stattdessen in val ändern würden, wäre das OK. Es ist wie eine Funktion, die immer das gleiche (zwischengespeicherte) Ergebnis liefert.

Wenn Sie zu einem var ähnliches Verhalten haben wollen Sie so etwas wie diese (durch explizite Setter und Getter hat) tun könnte:

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

Jetzt können Sie tun, was Sie mit einem var :) tun könnte.

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

Entschuldigung - Ich habe einen Fehler gemacht - die ursprüngliche Trait-Methode hätte auch geschützt werden sollen. Ich bin mir nicht sicher, ob ich dir zustimme, dass es logisch unmöglich ist, ein 'def 'mit einem' var' zu überschreiben. Alles was mein 'def' sagt, ist, dass ich erwarte, dass es einen Accessor namens' foo' gibt, der einen String zurückgibt - ein 'var' zu deklarieren ist eine Implementierung dieser –

+0

Ich denke ich stimme dir zu. Ich dachte daran, als eine strengere Idee zu überschreiben, als ich die Antwort schrieb. Ich werde die Antwort bearbeiten und eine praktikable Lösung bereitstellen :). –

+0

Es ist eine Schande, dass es keine "override def as var" -Syntax gibt –

Verwandte Themen