Можно ли добавить метод к встроенному типу в Scala?

StackOverflow https://stackoverflow.com/questions/298074

Вопрос

Я хотел бы добавить метод к встроенному типу (например,Double), так что я могу использовать infix оператор.Это возможно?

Это было полезно?

Решение

Да и нет.Да, ты можешь это сделать казаться как будто вы добавили метод в double.Например:

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

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

Этот код добавляет ранее недоступный <> оператор для любого объекта типа Double.Пока doubleToSyntax метод находится в области видимости, поэтому его можно вызывать без уточнений, будет работать следующее:

3.1415 <> 2.68     // => true

Часть ответа «нет» исходит из того факта, что вы на самом деле ничего не добавляете к Double сорт.Вместо этого вы создаете конверсию из Double к новому типу, который определяет нужный вам метод.Это может быть гораздо более мощный метод, чем открытые классы, предлагаемые многими динамическими языками.Кроме того, он полностью типобезопасен.:-)

Некоторые ограничения, о которых вам следует знать:

  • Эта техника не позволяет вам удалять или переопределить существующие методы, просто добавьте новые
  • Метод неявного преобразования (в данном случае doubleToSyntax) обязательно должен находиться в области видимости, чтобы желаемый метод расширения был доступен.

Идиоматически неявные преобразования либо помещаются в одноэлементные объекты, либо импортируются (например, import Predef._) или внутри признаков и унаследовано (например. class MyStuff extends PredefTrait).

Небольшое отступление:«Инфиксные операторы» в Scala на самом деле являются методами.Никакой магии, связанной с <> метод, который позволяет ему быть инфиксным, синтаксический анализатор просто принимает его таким.Если хотите, вы также можете использовать «обычные методы» в качестве инфиксных операторов.Например, Stream класс определяет take метод, который принимает один Int параметр и возвращает новый Stream.Это можно использовать следующим образом:

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

А str take 5 выражение буквально идентично str.take(5).

Другие советы

Эта функция пригодилась для реализации класса, выполняющего оценку ошибок:

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
  }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top