2009-05-04 18 views
16

Estoy intentando escribir un código Scala que hay que hacer algo como:Abstract Parámetros Tipos/Tipo de Scala

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

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

+0

¿Qué es una pregunta? – stepancheg

+0

¿Cómo hago esto? – bsdfish

Respuesta

28

Como usted señala, C++ tiene plantillas. En resumen, C++ dice que "hay una Prueba para todos los tipos T que compila Prueba". Eso hace que sea fácil agregar implícitamente restricciones en T, pero en el lado negativo están implícitas y puede ser difícil para un usuario de su clase entender 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 "test de clase [T]" está diciendo "para todo T existe un tipo Test [T]" sin restricción. Es más fácil razonar formalmente, pero significa que tienes que ser explícito sobre las restricciones. Por ejemplo, en Scala puede decir "prueba de clase [T <: Foo]" para decir que T debe ser un subtipo de Foo.

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

Hay algunas maneras de resolver su problema en Scala. Uno es typesafe pero un bt más detallado. El otro no es seguro.

La forma typesafe parece

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

A continuación, puede tener un cuerpo de fábricas para este tipo de ú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 la biblioteca tienen sus propias fábricas entonces pueden añadir 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 typesafe utiliza la reflexión y una característica en la Scala llama manifiesta que son una manera de moverse por una restricción de Java con respecto al tipo de borrado

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

Con esta versión se siguen escribiendo

class Foo 
val t = new Test[Foo] 

sin embargo, si no hay un constructor sin argumentos disponibles se obtiene 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) 
+0

¿Funciona alguno de estos enfoques con constructores basados ​​en parámetros para T? –

Cuestiones relacionadas