2013-11-03 31 views
7

Mi piace molto la sintassi ** per pow, disponibile in molte lingue (come Python).Creazione di `**` power operator per Scala?

È possibile introdurre questo in Scala, senza modificare il codice 'base' di Scala?

mio tentativo di Int una sola:

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

(lo vedono in mancanza sul IDEone)

+7

Si noti che '**' né '^' non avranno la precedenza a destra (questo è il motivo per cui lo stdlib non lo include). '4 * 5 ** 3' è' (4 * 5) ** 3' e non '4 * (5 ** 3)'. – sschaef

+0

Scala potrebbe modificare i propri metodi di analisi su una grammatica non LL (1); per esempio: vedi come C++ gestisce più '>' '<' deterministicamente –

risposta

11

questo funziona per me: (problema # 1 pow è definito in doppie, problema # 2 che si estende AnyVal) (anche non v'è alcun punto di avere quei backticks nel 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

Questo è piuttosto interessante. –

12

Questa risposta è di 2 anni di ritardo, ancora fo Per il beneficio degli altri, vorrei sottolineare che la risposta accettata si estende inutilmente da AnyVal.

C'è solo un piccolo bug che deve essere corretto nella risposta originale. Il metodo def ** richiede un solo parametro, vale a dire l'esponente poiché la base è già passata nel costruttore e non due come nel codice originale. Fissaggio e la rimozione che i risultati backticks in:

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

Che funziona come previsto come visto here.

Scala compilatore lancerà un Int ad un PowerIntsolo se il metodo che si chiama su di esso non è definito. Ecco perché non è necessario estendere da AnyVal.

Dietro le quinte, Scala cerca una classe implicita il cui tipo di argomento costruttore è uguale al tipo dell'oggetto che viene lanciato. Poiché l'oggetto può avere un solo tipo, le classi implicite non possono avere più di un argomento nel loro costruttore. Inoltre, se si definiscono due classi implicite con lo stesso tipo di costruttore, assicurarsi che le loro funzioni abbiano firme univoche altrimenti Scala non saprebbe a quale classe eseguire il cast e si lamenterà dell'ambiguità.

1

C'è un modo per rendere la soluzione un po 'più generico utilizzando 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()) 
}