Comment puis-je spécifier un type lié à flotteur et double sur un type générique Scala?
-
27-09-2019 - |
Question
Je suis en train d'écrire quelques simples cours vectorielles et matricielles. Ils ressemblent à ceci:
// 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)
}
Si je vais avec des méthodes et des autres classes comme Point3f / d, Vector4f / j, Matrix3f / j, Matrix4f / d ... cela va être beaucoup de travail. Uff ... Donc, je pensais que les médicaments génériques pourrait possible l'aide ici et supprimer la redondance de ma base de code. Je pensais à quelque chose comme ceci:
// 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]
L'idée est que le compilateur scala génère des classes spécialisées pour Vector3 [Float] et Vector3 [Double] similaire en C ++ modèle ferait. Malheureusement, je dois mettre un certain type lié au paramètre de type [T] de classe Vector3 telle que l'opérateur + est défini sur T. Ma question: Comment puis-je écrire Vector3 [Float] qu'il a les mêmes caractéristiques de performance que Vector3f? Contexte:. Je voudrais utiliser les classes Vector3f / Vector3D dans le code de détection de collision ... si la performance est importante pour moi
La solution
Utiliser un contexte lié de Fractional:
case class Vector3[@specialized(Float, Double) T : Fractional](x: T, y: T, z: T) { ...
puis dans le corps de la classe, obtenir une instance des opérateurs arithmétiques:
val fractOps = implicitly[Fractional[T]]
enfin importer ses membres dans le cadre de la classe:
import fractOps._
Vous pouvez ensuite écrire des opérations infixes ordinaires sur les valeurs de type T utilisé dans la classe. Malheureusement, vous devrez utiliser fractOps.div(a, b)
au lieu de a / b
pour la division.