2010-01-02 9 views
33

L'exemple suivant provient du livre 'Programming in Scala'. Étant donné une classe « rationnelle » et la définition de méthode suivante:Scala: méthode surcharge de l'opérateur

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

Je peux surcharger avec succès la méthode d'ajout d'une version pratique qui prend un argument Int et utilise la définition ci-dessus:

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

Aucun problème jusqu'à présent.

Maintenant, si je change le nom de la méthode à un nom de style de l'opérateur:

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

Et surcharge comme ceci:

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

Je reçois l'erreur de compilation suivante:

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

Pourquoi le compilateur recherche-t-il une version unaire de la méthode +?

Répondre

50

En Scala, toute construction du type +x, -x, ~x et !x est transformé en un appel de méthode x.unary_+, etc. Ceci est en partie pour permettre la syntaxe de type Java d'avoir !b comme la négation du b booléenne, ou -x comme la négation du nombre x.

Par conséquent, l'extrait de code +(new Rational(that, 1)) est converti en et comme Rational n'a pas cette méthode, vous obtenez une erreur de compilation. Vous obtiendrez cette erreur uniquement si votre fonction est appelée +, -, ~ ou ! car ce sont les seuls caractères que Scala autorise comme opérateurs unaires. Par exemple, si vous avez appelé votre fonction @+, le code compile très bien.

Bien, je vous suggère d'écrire la fonction add surchargée comme:

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

Ce code indique l'intention de votre fonction mieux - vous ajoutez un nouveau Rational construit à partir d'un entier comme un numérateur et 1 comme dénominateur à this. Cette façon d'écrire est traduite en this.+(new Rational(that, 1)), ce qui est ce que vous voulez - en appelant la fonction + sur this.

Notez que vous pouvez utiliser la notation infixe, mais la fonction est appelée. Par exemple, si vous modifiez le nom de retour à add, vous pouvez toujours garder la définition:

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

Vous n'avez pas spécifié l'opérateur binaire +, vous avez spécifié l'opérateur unaire +.

Ainsi, au lieu de:

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

Vous devez écrire ceci:

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

Si vous appelez + avec explicite this, il devrait fonctionner

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

Scala permet de définir les opérateurs unaires qui peuvent être utilisés dans la notation de l'opérateur de préfixe. Par exemple, vous pouvez utiliser + comme opérateur de préfixe pour obtenir le même:

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

Sans explicite this dans votre exemple, le compilateur pense que vous utilisez l'opérateur unaire + qui n'est pas défini.

Questions connexes