Tipos abstratos / Tipo Parâmetros em Scala
Pergunta
Eu estou tentando escrever algum código Scala que precisa fazer algo como:
class Test[Type] {
def main {
SomeFunc classOf[Type]
val testVal: Type = new Type()
}
}
e está falhando. Eu, obviamente, não estou entendendo alguma coisa sobre parâmetros genéricos Scala. Claramente, o mal-entendido é que, em C ++, modelos essencialmente funcionam como substituições de corda, tão novo Type () funcionará enquanto a classe que está sendo passado em tem um construtor padrão. No entanto, em Scala, tipos diferentes tipos de objetos.
Solução
Como salienta, C ++ tem modelos. Em suma, C ++ diz que "não é um teste para todos os tipos de T tais que compila teste." Isso torna mais fácil para adicionar implicitamente restrições em T, mas no lado de baixo Eles são implícita e pode ser difícil para um usuário de sua classe a compreender sem ler código.
polimorfismo paramétrico de Scala (aka genéricos) trabalho muito mais como ML, Haskell, Java e C #. Em Scala, quando você escreve "classe de teste [T]" você está dizendo "para todos T existe um tipo de teste [T]", sem restrição. Isso é mais simples de raciocinar sobre formalmente, mas isso não significa que você tem que ser explícito sobre restrições. Por exemplo, no Scala você pode dizer "classe de teste [T <: Foo]" para dizer que T deve ser um subtipo de Foo.
C # tem uma maneira de adicionar uma restrição a T em relação construtores, mas infelizmente Scala não.
Há um par de maneiras de resolver o seu problema no Scala. Um deles é typesafe mas um bt mais detalhado. O outro não é typesafe.
Os typesafe forma se parece com
class Test[T](implicit val factory : () => T) {
val testVal = factory
}
Em seguida, você pode ter um corpo de fábricas para tipos úteis em seu sistema
object Factories {
implicit def listfact[X]() = List[X]()
implicit def setfact[X]() = Set[X]()
// etc
}
import Factories._
val t = new Test[Set[String]]
Se os usuários de sua necessidade biblioteca suas próprias fábricas, em seguida, eles podem adicionar seu próprio equivalente do objeto fábricas. Uma vantagem desta solução é que qualquer coisa com uma fábrica pode ser usado, se há ou não um construtor sem argumento.
O não-tão-typesafe maneira usos reflexão e uma característica em Scala chamados manifestos que são uma maneira de contornar uma restrição Java quanto ao tipo apagamento
class Test[T](implicit m : Manifest[T]) {
val testVal = m.erasure.newInstance().asInstanceOf[T]
}
Com esta versão você ainda write
class Foo
val t = new Test[Foo]
No entanto, se há construtor não não-arg disponível você obter uma exceção de tempo de execução em vez de um tipo estático erro
scala> new Test[Set[String]]
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)