Question

J'essaie d'écrire du code Scala qui doit faire quelque chose comme:

class Test[Type] { 
   def main {
       SomeFunc classOf[Type]
       val testVal: Type = new Type()
    }
 }

et ça échoue. Je ne comprends évidemment pas quelque chose au sujet des paramètres génériques Scala. Il est clair que le malentendu est qu’en C ++, les modèles fonctionnent essentiellement comme des substitutions de chaînes, de sorte que new Type () fonctionnera aussi longtemps que la classe en cours de transmission possède un constructeur par défaut. Cependant, dans Scala, les types sont différents types d'objets.

Était-ce utile?

La solution

Comme vous le signalez, C ++ a des modèles. En bref, C ++ dit & "Il existe un Test pour tous les types T tels que Test soit compilé. &"; Cela facilite l'ajout implicite de contraintes sur T, mais elles sont implicites et peuvent être difficiles à comprendre pour un utilisateur de votre classe sans lire le code.

Le polymorphisme paramétrique de Scala (ou génériques) fonctionne beaucoup plus comme ML, Haskell, Java et C #. En Scala, lorsque vous écrivez & Quot; test de classe [T] & Quot; vous dites & "; pour tout T, il existe un type Test [T] &"; sans contrainte. C'est plus simple de raisonner de manière formelle, mais cela signifie que vous devez être explicite sur les contraintes. Par exemple, en Scala, vous pouvez dire & "Test de classe [T & Lt ;: Foo] &"; dire que T doit être un sous-type de Foo.

C # a le moyen d’ajouter une contrainte à T concernant les constructeurs, mais malheureusement pas Scala.

Il existe plusieurs façons de résoudre votre problème en Scala. L'un est typé mais un plus bavard. L'autre n'est pas typé.

La méthode de typographie ressemble à

class Test[T](implicit val factory : () => T) {
  val testVal = factory
}

Ensuite, vous pouvez avoir un corps d'usines pour les types utiles dans votre système

object Factories {
  implicit def listfact[X]() = List[X]()
  implicit def setfact[X]() = Set[X]()
  // etc
}

import Factories._
val t = new Test[Set[String]]

Si les utilisateurs de votre bibliothèque ont besoin de leurs propres usines, ils peuvent ajouter leur propre équivalent de l'objet Factories. L'un des avantages de cette solution est que tout ce qui est associé à une usine peut être utilisé, qu'il y ait ou non un constructeur sans argument.

La méthode pas-si-typesafe utilise la réflexion et une fonctionnalité de Scala appelée manifestes, qui permet de contourner une contrainte Java relative à l'effacement de types

 class Test[T](implicit m : Manifest[T]) {
   val testVal = m.erasure.newInstance().asInstanceOf[T]
 }

Avec cette version, vous écrivez toujours

class Foo
val t = new Test[Foo]

Cependant, s'il n'y a pas de constructeur no-arg disponible, vous obtenez une exception d'exécution à la place d'une erreur de type statique

scala> new Test[Set[String]] 
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top