Pregunta

Estoy tratando de escribir un código Scala que necesita hacer algo como:

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

y está fallando. Obviamente no entiendo algo sobre los parámetros genéricos de Scala. Claramente, el malentendido es que en C ++, las plantillas funcionan esencialmente como sustituciones de cadenas, por lo que el nuevo Type () funcionará siempre que la clase que se pasa tenga un constructor predeterminado. Sin embargo, en Scala, los tipos son diferentes tipos de objetos.

¿Fue útil?

Solución

Como señala, C ++ tiene plantillas. En resumen, C ++ dice & "; Hay una Prueba para todos los tipos T de modo que la Prueba compila. &"; Eso hace que sea fácil agregar implícitamente restricciones en T, pero en el lado negativo son implícitas y puede ser difícil de entender para un usuario de su clase sin leer el código.

El polimorfismo paramétrico de Scala (también conocido como genéricos) funciona mucho más como ML, Haskell, Java y C #. En Scala, cuando escribe & Quot; clase Test [T] & Quot; estás diciendo " para todo T existe un tipo Test [T] " sin restricciones Eso es más simple de razonar formalmente, pero significa que tienes que ser explícito sobre las restricciones. Por ejemplo, en Scala puede decir & Quot; class Test [T & Lt ;: Foo] & Quot; decir que T debe ser un subtipo de Foo.

C # tiene una manera de agregar una restricción a T con respecto a los constructores, pero desafortunadamente Scala no.

Hay un par de formas de resolver su problema en Scala. Uno es typesafe pero un poco más detallado. El otro no es seguro para escribir.

La forma segura de escribir parece

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

Entonces puede tener un cuerpo de fábricas para tipos útiles en su sistema

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

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

Si los usuarios de su biblioteca necesitan sus propias fábricas, entonces pueden agregar su propio equivalente del objeto Fábricas. Una ventaja de esta solución es que se puede usar cualquier cosa con una fábrica, ya sea que haya o no un constructor sin argumentos.

La forma no tan segura de tipos utiliza la reflexión y una característica en Scala llamada manifiestos que son una forma de sortear una restricción de Java con respecto al borrado de tipos

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

Con esta versión todavía escribes

class Foo
val t = new Test[Foo]

Sin embargo, si no hay un constructor sin argumentos disponibles, obtendrá una excepción de tiempo de ejecución en lugar de un error de tipo estático

scala> new Test[Set[String]] 
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top