2013-11-03 19 views
7

Podobają mi się składnia ** dla pow, dostępna w wielu językach (takich jak Python).Tworzenie `` `operatora mocy dla Scala?

Czy można wprowadzić to w Scali, bez modyfikowania kodu "podstawowego" Scala?

Moja próba na Int tylko jeden:

import scala.math.pow 
implicit class PowerInt(i: Int) { 
    def `**`(n: Int, b: Int): Int = pow(n, b).intValue 
} 

(patrz że w przypadku braku na IDEone)

+7

Zauważ, że '**' ani '^' nie będzie miał prawo pierwszeństwa (to jest powód, dlaczego stdlib nie obejmuje tego). '4 * 5 ** 3' to' (4 * 5) ** 3', a nie '4 * (5 ** 3)'. – sschaef

+0

Scala może zmienić ich metody analizowania na gramatykę inną niż LL (1); np .: zobacz, jak C++ obsługuje wiele '>' '<' deterministycznie –

Odpowiedz

11

działa to dla mnie: (problem nr 1 pow określa się na deblu, Zadanie nr 2 rozszerzenie anyval) (również nie ma sensu posiadania te odwrócone, pojedyncze apostrofy w methodName?)

import scala.math.pow 

object RichIntt { 

    implicit class PowerInt(val i:Double) extends AnyVal { 
    def ** (exp:Double):Double = pow(i,exp) 
    } 

    def main(args:Array[String]) 
    { 
    println(5**6) 
    } 

} 
+1

To jest całkiem fajne. –

12

Ta odpowiedź jest 2 lata późno, nadal fo z korzyścią dla innych Chciałbym zaznaczyć, że zaakceptowana odpowiedź niepotrzebnie rozciąga się od AnyVal.

Istnieje tylko niewielki błąd, który należy poprawić w oryginalnej odpowiedzi. Metoda def ** wymaga tylko jednego parametru, tj. Wykładnik jako podstawa jest już przekazywany w konstruktorze, a nie w dwóch, tak jak w oryginalnym kodzie. Ustalające, że i usuwanie wyników backticks w:

import scala.math.pow 
implicit class PowerInt(i: Int) { 
    def ** (b: Int): Int = pow(i, b).intValue 
} 

który działa zgodnie z oczekiwaniami, jak widać here.

Scala kompilator będzie rzutować Int Do PowerInttylko jeśli metoda, która jest wywoływana na nim jest niezdefiniowany. Dlatego nie musisz przedłużać z AnyVal.

Scala szuka za kulisami niejawnej klasy, której typ argumentu konstruktora jest taki sam, jak typ rzutowanego obiektu. Ponieważ obiekt może mieć tylko jeden typ, niejawne klasy nie mogą mieć więcej niż jeden argument w swoim konstruktorze. Ponadto, jeśli zdefiniujesz dwie niejawne klasy o tym samym typie konstruktora, upewnij się, że ich funkcje mają unikatowe podpisy, w przeciwnym razie Scala nie będzie wiedziała, do której klasy należy rzucać, i będzie narzekać na niejasności.

1

Jest na to sposób, aby rozwiązanie nieco bardziej ogólny używając Numeric typeclass:

implicit class PowerOp[T: Numeric](value: T) { 
    import Numeric.Implicits._ 
    import scala.math.pow 

    def **(power: T): Double = pow(value.toDouble(), power.toDouble()) 
}