Как указать тип, связанный с Float и Double на универсальном типе в Scala?
-
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
для разделения.