Как указать тип, связанный с Float и Double для универсального типа в Scala? - PullRequest
1 голос
/ 12 августа 2010

Я пишу несколько простых классов Vector и Matrix.Они выглядят так:

// Vector with Floats
case class Vector3f(x: Float, y: Float, z: Float) {
  def +(v: Vector3f) = Vector3f(x + v.x, y + v.y, z + v.z)
}

// Vector with Doubles
case class Vector3d(x: Double, y: Double, z: Double) {
  def +(v: Vector3d) = Vector3d(x + v.x, y + v.y, z + v.z)
}

Если я продолжу с другими методами и классами, такими как Point3f / d, Vector4f / d, Matrix3f / d, Matrix4f / d ... это будет многоРабота.Уф ... Так что я подумал, что дженерики могут помочь здесь и удалить избыточность из моей базы кода.Я думал о чем-то вроде этого:

// first I define a generic Vector class
case class Vector3[@specialized(Float, Double) T](x: T, y: T, z: T) {
   def +(v: Vector3[T]) = new Vector3[T](x + v.x, y + v.y, z + v.z)
}

// than I use some type aliases to hide the generic nature
type Vector3f = Vector3[Float]
type Vector3d = Vector3[Double]

Идея состоит в том, что компилятор scala генерирует специализированные классы для Vector3 [Float] и Vector3 [Double], аналогичные шаблонам C ++.К сожалению, я должен поставить некоторый тип, связанный с параметром типа [T] класса Vector3, чтобы оператор + был определен для T. Мой вопрос: как мне написать Vector3 [Float], чтобы он имел те же характеристики производительности, что и Vector3f?Контекст: я хотел бы использовать классы Vector3f / Vector3d в коде обнаружения столкновений ... поэтому для меня важна производительность.

1 Ответ

5 голосов
/ 12 августа 2010

Использовать контекстную границу Fractional:

case class Vector3[@specialized(Float, Double) T : Fractional](x: T, y: T, z: T)  { ...

затем в теле класса получите экземпляр арифметических операторов:

  val fractOps = implicitly[Fractional[T]]

наконец импортирует своих членов в область видимости класса:

  import fractOps._

После этого вы можете писать обычные инфиксные операции для значений типа T, используемых в классе. К сожалению, вам придется использовать fractOps.div(a, b) вместо a / b для деления.

...