2010-01-02 17 views
33

Das folgende Beispiel stammt aus dem Buch "Programming in Scala". Bei einer Klasse ‚Rational‘ und die folgende Methode Definition:Scala: method operator overloading

def add(that: Rational): Rational = 
    new Rational(
     this.numer * that.denom + that.numer * this.denom, 
     this.denom * that.denom 
    ) 

kann ich überlasten erfolgreich das Add-Methode mit einer Komfort-Version, die ein Int-Argument, und nutzt die Definition oben:

def add(that: Int): Rational = 
    add(new Rational(that, 1)) 

Keine Probleme bisher.

Nun, wenn ich ändere den Namen der Methode an einen Operator Artnamen:

def +(that: Rational): Rational = 
    new Rational(
     this.numer * that.denom + that.numer * this.denom, 
     this.denom * that.denom 
    ) 

Und Überlastung wie so:

def +(that: Int): Rational = 
    +(new Rational(that, 1)) 

erhalte ich den folgenden Compiler-Fehler:

(fragment of Rational.scala):19: error: value unary_+ is not a member of this.Rational 
+(new Rational(that, 1)) 
^ 

Warum sucht der Compiler nach einer unären Version der +-Methode?

Antwort

50

In Scala jedes Konstrukt vom Typ +x, -x, ~x!x und wird in einen Methodenaufruf transformiert x.unary_+, etc. Dies ist teilweise Java-ähnliche Syntax mit !b als die Negation der booleschen b zu ermöglichen, oder -x als die Negation der Nummer x.

Daher wird das Code-Snippet +(new Rational(that, 1)) in (new Rational(that,1)).unary_+ übersetzt, und da Rational diese Methode nicht hat, erhalten Sie einen Kompilierungsfehler. Sie erhalten diesen Fehler nur, wenn Ihre Funktion +, -, ~ oder ! aufgerufen wird, da dies die einzigen Zeichen sind, die Scala als unäre Operatoren zulässt. Zum Beispiel, wenn Sie Ihre Funktion @+ aufgerufen haben, kompiliert der Code einfach gut.

Obwohl, ich würde vorschlagen, die überschriebene Zusatzfunktion wie das Schreiben:

def +(that: Int): Rational = 
    this + (new Rational(that, 1)) 

Dieser Code die Absicht Ihrer Funktion zeigt besser - Sie ein neues Rational aus einer ganzen Zahl als Zähler und Nenner 1 als konstruiert hinzufügen zu this. Diese Art zu schreiben wird übersetzt in this.+(new Rational(that, 1)), was Sie wollen - Aufruf der + Funktion auf this.

Beachten Sie, dass Sie die Infix-Notation verwenden können, jedoch wird die Funktion aufgerufen. Zum Beispiel, wenn Sie den Namen add zurück zu ändern, können Sie immer noch die Definition halten, wie:

def add(that: Int): Rational = 
    this add (new Rational(that, 1)) 
3

Sie haben nicht den binären Operator + angegeben, haben Sie den unären Operator + angegeben.

Also statt:

def +(that: Int): Rational = 
    +(new Rational(that, 1)) 

Sie müssen dies schreiben:

def +(that: Int): Rational = 
    this +(new Rational(that, 1)) 
5

Wenn Sie + mit expliziten this nennen, sollte es

def +(that: Int): Rational = this.+(new Rational(that, 1)) 

Scala arbeiten können definieren unäre Operatoren, die in der Präfixoperatornotation verwendet werden können. Zum Beispiel können Sie + als Präfix-Operator verwenden, das gleiche zu erreichen:

def unary_+: Rational = this.+(new Rational(that, 1)) 
val a = new Rational(3,2) 
val b = +a 

Ohne ausdrückliche this in Ihrem Beispiel, denkt der Compiler, dass Sie unärer Operator + verwenden, die nicht definiert ist.