2010-01-02 14 views
33

Poniższy przykład pochodzi z książki "Programowanie w Scali". Biorąc pod uwagę klasę „Rational” i następującą definicję metoda:Scala: method operator overloading

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

mogę skutecznie przeciążyć metodę dodawania z wersji convenience że przyjmuje argument int, a korzysta z definicją powyżej:

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

Żadnych problemów do tej pory.

Teraz, jeśli zmienię nazwę metody do nazwy stylu operator:

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

i przeciążeniem tak:

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

otrzymuję następujący błąd kompilacji:

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

Dlaczego kompilator szuka jednolitej wersji metody +?

Odpowiedz

50

Scala, każda konstrukcja typu +x, -x, ~x i !x przekształca wywołanie metody x.unary_+, itd. Jest to częściowo pozwala składni Java-podobnych o !b jako negację logiczną b lub -x jako zaprzeczenie liczby x.

Dlatego fragment kodu jest tłumaczony na , a ponieważ Rational nie ma tej metody, pojawia się błąd kompilacji. Otrzymasz ten błąd tylko wtedy, gdy twoja funkcja nazywa się +, -, ~ lub !, ponieważ są to jedyne znaki, które Scala dopuszcza jako operatory jednoargumentowe. Na przykład, jeśli wywołasz swoją funkcję @+, kod kompiluje się dobrze.

Chociaż, chciałbym zaproponować napisanie zastąpiona funkcji Dodaj:

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

Ten kod wskazuje na intencje swojej funkcji lepszego - dodać nowy Rational zbudowany z liczb całkowitych jako licznik i mianownik 1 jako do this. Ten sposób pisania zostaje przetłumaczony na this.+(new Rational(that, 1)), co jest potrzebne - wywołanie funkcji + na this.

Należy pamiętać, że można używać notacji infiksowej, jednak funkcja jest wywoływana. Na przykład, jeśli zmieni nazwę z powrotem do add, nadal można zachować definicję jak:

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

Nie podano operator binarny +, masz określony operator jednoargumentowy +.

Więc zamiast:

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

Musisz napisać tak:

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

Jeśli zadzwonisz + z wyraźną this, to powinno działać

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

Scala pozwala na zdefiniowanie jednoargumentowe operatory, które mogą być używane w notacji operatora przedrostka. Na przykład można użyć + jako operator przedrostka, aby osiągnąć ten sam:

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

bez wyraźnej this w przykładzie, kompilator myśli, że jesteś z wykorzystaniem pojedynczego operatora + który nie jest zdefiniowany.