2008-11-18 18 views

Respuesta

17

Sí y no. Sí, puede hacer que parezca como que ha agregado un método al double. Por ejemplo:

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

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

Este código añade el <> operador previamente disponible a cualquier objeto de tipo Double. En tanto que el método doubleToSyntax está en el ámbito de modo que pudiera ser invocado sin calificación, el siguiente trabajo:

3.1415 <> 2.68  // => true 

La parte "no" de la respuesta viene del hecho de que usted no está realmente añadir nada a la clase Double. En cambio, está creando una conversión de Double a un nuevo tipo que define el método que desea. Esta puede ser una técnica mucho más poderosa que las clases abiertas que ofrecen muchos lenguajes dinámicos. También pasa a ser completamente seguro para tipos. :-)

Algunas limitaciones que debe tener en cuenta:

  • Esta técnica no permite que eliminar o redefinir métodos existentes, sólo tiene que añadir otras nuevas
  • El método de conversión implícita (en este caso, doubleToSyntax) debe ser absolutamente en-alcance para el método de extensión deseado a estar disponible

idiomático, c implícita las onversiones se colocan dentro de objetos singleton y se importan (p. import Predef._) o dentro de los rasgos y heredado (por ejemplo, class MyStuff extends PredefTrait).

Poco a un lado: los "operadores de infijo" en Scala son en realidad métodos. No hay magia asociada con el método <> que le permite ser infijo, el analizador simplemente lo acepta de esa manera. También puede usar "métodos regulares" como operadores de infijo si lo desea. Por ejemplo, la clase Stream define un método take que toma un solo parámetro Int y devuelve un nuevo Stream. Esto se puede utilizar de la siguiente manera:

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

La expresión str take 5 es literalmente idénticos a str.take(5).

+0

Usted puede utilizar la sintaxis class' implícita 'para simplificar esto un poco. – lmm

1

Esta característica fue práctico para implementar una estimación de error al realizar la clase:

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

Eso es realmente un poco limpio. :) –

Cuestiones relacionadas