كيف يمكنني تحديد نوع ملزم بالعائمة ومضاعفة على نوع عام في 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 يولد فئات متخصصة لـ Vector3 [Float] و Vector3 [double] مماثلة كما يفعل قالب C ++. لسوء الحظ ، لا بد لي من وضع نوع ملزم بمعلمة النوع [t] من Vector3 بحيث يتم تعريف المشغل + على 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._
بعد ذلك يمكنك كتابة عمليات Infix عادية على قيم النوع T المستخدمة داخل الفصل. للأسف ، سيكون عليك استخدام fractOps.div(a, b)
بدلاً من a / b
للقسمة.