Scala 2.8 L'utilisation, vous pourrait écrire:
case class Vector3[T: Numeric](val x: T, val y: T, val z: T) {
override def toString = "(%s, %s, %s)" format (x, y, z)
def add(that: Vector3[T]) = new Vector3(
plus(x, that.x),
plus(y, that.y),
plus(z, that.z)
)
private def plus(x: T, y: T) = implicitly[Numeric[T]] plus (x, y)
}
Laissez-moi expliquer. Tout d'abord, T: Numeric
est un contexte lié qui fournit implicitement une instance Numeric[T]
à votre classe.
Le trait Numeric[T]
fournit des opérations sur les types numériques,
trait Numeric[T] extends Ordering[T] {
def plus(x: T, y: T): T
def minus(x: T, y: T): T
def times(x: T, y: T): T
def negate(x: T): T
// other operations omitted
}
L'expression implicitly[Numeric[T]]
récupère ce contexte implicite de telle sorte que vous pouvez effectuer les opérations telles que plus
sur vos arguments concrets x, y et z, comme illustré dans la méthode privée ci-dessus.
Vous pouvez maintenant construire et add
différentes instanciations de Vector3
tels que des Int
's et Double
' s:
scala> Vector3(1,2,3) add Vector3(4,5,6)
res1: Vector3[Int] = (5, 7, 9)
scala> Vector3(1.1, 2.2, 3.3) add Vector3(4.4, 5.5, 6.6)
res2: Vector3[Double] = (5.5, 7.7, 9.899999999999999)
Side note: Il est possible d'utiliser des conversions implicites pour convertir les valeurs aux instances Numeric[T].Ops
telles que ce qui suit pourrait être écrit à la place:
def add(that: Vector3[T]) = new Vector3(x + that.x, y + that.y, z + that.z)
J'ai délibérément choisi de ne pas utiliser ces conversions implicites car ils (peuvent) engager des performanc Pénalité en créant des objets wrapper temporaires. L'impact réel sur les performances dépend de la JVM (par exemple, dans quelle mesure ses supports échappent à l'analyse pour éviter l'allocation effective d'objets sur heap). Utiliser un contexte lié et implicitly
évite ce surcoût potentiel ... au prix d'une certaine verbosité.
Dans 2.8 c'est 'Ops', ou alors on me dit. Je n'ai aucune idée de ce qu'il faut faire en 2.7, mais je suis nouveau à Scala. – erisco