Domanda

Vorrei aggiungere un metodo a un tipo incorporato (ad esempio Double), in modo da poter utilizzare un infix operatore. È possibile?

È stato utile?

Soluzione

Sì e no. Sì, puoi farlo sembrare come se avessi aggiunto un metodo a double. Ad esempio:

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

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

Questo codice aggiunge l'operatore <> precedentemente non disponibile a qualsiasi oggetto di tipo Double. Finché il metodo doubleToSyntax rientra nell'ambito in modo che possa essere invocato senza qualifica, funzionerà quanto segue:

3.1415 <> 2.68     // => true

Il " no " parte della risposta deriva dal fatto che non stai davvero aggiungendo nulla alla classe import Predef._. Invece, stai creando una conversione da class MyStuff extends PredefTrait a un nuovo tipo che definisce il metodo desiderato. Questa può essere una tecnica molto più potente delle classi aperte offerte da molti linguaggi dinamici. Capita anche di essere completamente sicuro. : -)

Alcune limitazioni di cui dovresti essere a conoscenza:

  • Questa tecnica non ti consente di rimuovere o ridefinire metodi esistenti, basta aggiungerne di nuovi
  • Il metodo di conversione implicita (in questo caso, Stream) deve essere assolutamente nell'ambito affinché il metodo di estensione desiderato sia disponibile

Idiomaticamente, le conversioni implicite vengono collocate all'interno di oggetti singleton e importate (ad esempio take) o all'interno di tratti e ereditate (ad esempio Int).

Leggero a parte: " infix operatori " in Scala sono in realtà metodi. Non esiste alcuna magia associata al metodo str take 5 che gli consente di essere infettato, il parser semplicemente lo accetta in quel modo. Puoi anche usare & Quot; metodi regolari & Quot; come operatori infix, se lo desideri. Ad esempio, la classe str.take(5) definisce un metodo <=> che accetta un singolo <=> parametro e restituisce un nuovo <=>. Questo può essere usato nel modo seguente:

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

L'espressione <=> è letteralmente identica a <=>.

Altri suggerimenti

Questa funzionalità è stata utile per implementare una classe che esegue una stima degli errori:

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
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top