Как указать тип, связанный с Float и Double на универсальном типе в Scala?

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

  •  27-09-2019
  •  | 
  •  

Вопрос

Я пишу несколько простых векторных и матричных классов. Они похожи на это:

// 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 ... Это будет много работы. UFF ... поэтому я думал, что дженерики могут помочь здесь и удалить избыточность с моей кодовой базы. Я думал о чем-то вроде этого:

// 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 Compiler генерирует специализированные классы для вектора 3 [Float] и Vector3 [Double], аналогично, как шаблон C ++. К сожалению, мне приходится поставить несколько типов, связанных на параметре типа [T] в векторе класса3, так что оператор + определяется на T. Мой вопрос: как я могу написать вектор3 [Float], что он имеет те же характеристики производительности, что и Vector3F? Контекст: я хотел бы использовать классы Vector3F / Vector3D в коде обнаружения столкновения ... Так что производительность имеет значение для меня.

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

Решение

Используйте границу контекста дробного:

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 для разделения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top