2008-11-18 6 views

Répondre

17

Oui et non. Oui, vous pouvez le faire semblent comme si vous avez ajouté une méthode à double. Par exemple:

class MyRichDouble(d: Double) { 
    def <>(other: Double) = d != other 
} 

implicit def doubleToSyntax(d: Double) = new MyRichDouble(d) 

Ce code ajoute l'opérateur <> précédemment indisponibles pour tout objet de type Double. Tant que la méthode doubleToSyntax est portée afin qu'il puisse être invoqué sans qualification, ce qui suit fonctionnera:

3.1415 <> 2.68  // => true 

Le « non » une partie de la réponse vient du fait que vous n'êtes pas vraiment rien ajouter à la classe Double. Au lieu de cela, vous créez une conversion de Double à un nouveau type qui définit la méthode que vous souhaitez. Cela peut être une technique beaucoup plus puissante que les classes ouvertes offertes par de nombreux langages dynamiques. Il arrive aussi à être complètement sûr de type. :-)

Certaines limitations que vous devez être au courant:

  • Cette technique ne vous permet pas de supprimer ou redéfinissent méthodes existantes, il suffit d'ajouter de nouvelles
  • La méthode de conversion implicite (dans ce cas, doubleToSyntax) doit absolument être dans le champ d'application pour que la méthode d'extension désirée soit disponible

Idiomatiquement, implicitement c Les inversions sont placées dans des objets singleton et importées (par ex. import Predef._) ou au sein des traits et hérités (par exemple, class MyStuff extends PredefTrait). Légèrement à part: les "opérateurs infixes" dans Scala sont en fait des méthodes. Il n'y a pas de magie associée à la méthode <> qui lui permet d'être infixe, l'analyseur l'accepte simplement comme ça. Vous pouvez également utiliser des "méthodes régulières" comme opérateurs infix si vous le souhaitez. Par exemple, la classe Stream définit une méthode take qui prend un seul paramètre Int et renvoie un nouveau Stream. Ceci peut être utilisé de la manière suivante:

val str: Stream[Int] = ... 
val subStream = str take 5 

L'expression str take 5 est littéralement identique à str.take(5).

+0

Vous pouvez utiliser la syntaxe 'class' implicite pour simplifier un peu. – lmm

1

Cette fonction est bien pratique pour mettre en œuvre une estimation d'erreur performante de classe:

object errorEstimation { 
    class Estimate(val x: Double, val e: Double) { 
    def + (that: Estimate) = 
     new Estimate(this.x + that.x, this.e + that.e) 
    def - (that: Estimate) = 
     new Estimate(this.x - that.x, this.e + that.e) 
    def * (that: Estimate) = 
     new Estimate(this.x * that.x, 
        this.x.abs*that.e+that.x.abs*this.e+this.e*that.e) 
    def/(that: Estimate) = 
     new Estimate(this.x/that.x, 
        (this.x.abs*that.e+that.x.abs*this.e)/(that.x.abs*(that.x.abs-that.e))) 
    def +- (e2: Double) = 
     new Estimate(x,e+e2) 
    override def toString = 
     x + " +- " + e 
    } 
    implicit def double2estimate(x: Double): Estimate = new Estimate(x,0) 
    implicit def int2estimate(x: Int): Estimate = new Estimate(x,0) 

    def main(args: Array[String]) = { 
    println(((x: Estimate) => x+2*x+3*x*x)(1 +- 0.1)) 
    // 6.0 +- 0.93 
    println(((x: Estimate) => (((y: Estimate) => y*y + 2)(x+x)))(1 +- 0.1)) 
    // 6.0 +- 0.84 
    def poly(x: Estimate) = x+2*x+3/(x*x) 
    println(poly(3.0 +- 0.1)) 
    // 9.33333 +- 0.3242352 
    println(poly(30271.3 +- 0.0001)) 
    // 90813.9 +- 0.0003 
    println(((x: Estimate) => poly(x*x))(3 +- 1.0)) 
    // 27.037 +- 20.931 
    } 
} 
+0

C'est en fait un peu soigné. :) –

Questions connexes