2010-05-14 6 views
4

Donc j'apprends Scala pour l'instant, et j'essaie de créer une classe de vecteurs abstraite avec un espace vectoriel de 3 (coordonnées x, y, z). J'essaie d'ajouter deux de ces vecteurs avec le code suivant:Type de paramétrage dans Scala


package math 

class Vector3[T](ax:T,ay:T,az:T) { 
    def x = ax 
    def y = ay 
    def z = az 
    override def toString = "<"+x+", "+y+", "+z+">" 
    def add(that: Vector3[T]) = new Vector3(x+that.x, y+that.y, z+that.z) 
} 

Le problème est que je continue à obtenir cette erreur:

error: type mismatch;
found : T
required: String
def add(that: Vector3[T]) = new Vector3(x+that.x, y+that.y, z+that.z)

J'ai essayé de commenter le « toString » méthode ci-dessus, mais cela ne semble pas avoir d'effet. Quelqu'un peut-il me dire ce que je fais mal?

Répondre

7

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é.

6

Le problème est T. Il est de type Any, mais Any n'a pas d'opérateur +. L'erreur à propos de String est un peu manquante. Donc, vous allez devoir définir la limite min à un type qui le fait.

+1

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

8

Vous n'avez pas limité le paramètre de type T et le compilateur revient à l'interprétation de + comme concaténation de chaîne.

3

Les deux réponses de @sblundy et @Randall Schulz sont corrects, bien sûr, mais si vous avez besoin des conseils plus concrets sur la façon de limiter T alors que diriez-vous:

class Vector3[T <% Double](ax:T,ay:T,az:T) { 
... 
} 
Questions connexes