Ja, Sie haben recht, dass dies auf Löschen zurückzuführen ist - Sie wissen nichts über A
zur Laufzeit, dass Sie nicht explizit als Einschränkung in der Methodensignatur angegeben haben.
Typ Löschung auf der JVM nur teilweise ist, so dass Sie für die Klasse von einem Wert einige schreckliche Dinge in Scala fragen wie:
scala> List(1, 2, 3).getClass
res0: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon
Sobald du mit Generika erhalten, aber alles gelöscht ist, so zum Beispiel können Sie nicht den folgenden Dinge auseinander halten:
scala> List(1, 2, 3).getClass == List("a", "b", "c").getClass
res1: Boolean = true
(Falls es ist nicht klar, ich denke, Typ Löschung ist eindeutig eine gute Sache, und dass das einzige Problem mit Typ Löschung auf der JVM ist, dass es ist nicht vollständiger.)
Sie können schreiben folgendes:
import scala.reflect.{ ClassTag, classTag }
class G1[A: ClassTag](val a: A) {
val c: A = classTag[A].runtimeClass.newInstance().asInstanceOf[A]
}
Und es wie folgt verwenden:
scala> val stringG1: G1[String] = new G1("foo")
stringG1: G1[String] = [email protected]
scala> stringG1.c
res2: String = ""
Dies ist eine wirklich schlechte Idee, aber, da sie zur Laufzeit für viele, viele abstürzen Typ Parameter:
scala> class Foo(i: Int)
defined class Foo
scala> val fooG1: G1[Foo] = new G1(new Foo(0))
java.lang.InstantiationException: Foo
at java.lang.Class.newInstance(Class.java:427)
... 43 elided
Caused by: java.lang.NoSuchMethodException: Foo.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 43 more
Ein besserer Ansatz ist im Konstruktor übergeben:
class G1[A](val a: A)(empty:() => A) {
val c: A = empty()
}
Und ein viel besserer Ansatz ist es, eine Typklasse zu verwenden:
trait Empty[A] {
def default: A
}
object Empty {
def instance[A](a: => A): Empty[A] = new Empty[A] {
def default: A = a
}
implicit val stringEmpty: Empty[String] = instance("")
implicit val fooEmpty: Empty[Foo] = instance(new Foo(0))
}
class G1[A: Empty](val a: A) {
val c: A = implicitly[Empty[A]].default
}
Und dann:
scala> val fooG1: G1[Foo] = new G1(new Foo(10101))
fooG1: G1[Foo] = [email protected]
scala> fooG1.c
res0: Foo = [email protected]
Hier wir mit Bezug auf A
in der Definition von G1
, aber wir verweisen nur auf Eigenschaften und Operationen, die wir zur Zeit der Kompilierung bestätigt oder für verfügbar gehalten haben.
Es sieht so aus, als ob der Compiler nicht funktionieren kann. 'A' ist eine Klasse. Diese Frage sieht relevant aus: http://stackoverflow.com/questions/6200253/scala-classof-for-type-parameter (es verwendet 'classOf' statt' new' aber das Prinzip ist das gleiche, denke ich) –
Und zu Beantworten Sie Ihren Hauptpunkt allgemeiner, ja, Typ-Parameter können in Funktionskörpern erscheinen, um Rückgabetypen usw. zu deklarieren, wenn Sie einen Typ benötigen, aber Sie fordern mehr in Ihrem Code: dass der Typ als Klasse verwendet wird. –