Question

J'aimerais ajouter une méthode à un type intégré (par exemple, Double), afin de pouvoir utiliser un opérateur infix. Est-ce possible?

Était-ce utile?

La solution

Oui et non. Oui, vous pouvez donner l’apparence que vous avez ajoutée 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 indisponible à tout objet de type Double. Tant que la méthode doubleToSyntax est dans la portée pour pouvoir être invoquée sans qualification, les opérations suivantes fonctionneront:

3.1415 <> 2.68     // => true

Le " non " une partie de la réponse vient du fait que vous n’ajoutez rien à la classe import Predef._. Au lieu de cela, vous créez une conversion de class MyStuff extends PredefTrait vers un nouveau type qui définit la méthode souhaitée. Cela peut être une technique beaucoup plus puissante que les classes ouvertes offertes par de nombreux langages dynamiques. Il se trouve également qu’il est totalement sûr pour le type. : -)

Certaines limitations dont vous devez tenir compte:

  • Cette technique ne vous permet pas de supprimer ou de redéfinir les méthodes existantes, il vous suffit d'en ajouter de nouvelles
  • .
  • La méthode de conversion implicite (dans ce cas, Stream) doit absolument être dans la portée pour que la méthode d'extension souhaitée soit disponible

Idéalement, les conversions implicites sont soit placées dans des objets singleton et importées (par exemple, take), soit dans des traits et héritées (par exemple, Int).

Légère mise de côté: " infixer les opérateurs " Scala sont en fait des méthodes. Il n’existe pas de magie associée à la méthode str take 5 qui lui permette d’être infixée, l’analyseur l’accepte simplement de cette façon. Vous pouvez également utiliser & Quot; méthodes régulières & Quot; en tant qu'opérateurs infixes si vous aimez. Par exemple, la classe str.take(5) définit une méthode <=> qui utilise un seul paramètre <=> et renvoie un nouveau <=>. Ceci peut être utilisé de la manière suivante:

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

L'expression <=> est littéralement identique à <=>.

Autres conseils

Cette fonctionnalité est très utile pour implémenter une classe effectuant une estimation d'erreur:

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
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top