是的,你说得对,这是因为擦除 - 你不知道A
在运行时什么都没有明确声明它是方法签名中的一个约束。
在JVM类型擦除仅仅是局部的,所以你可以做一些可怕的事情在斯卡拉像索要类的值:
scala> List(1, 2, 3).getClass
res0: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon
一旦你到仿制药,不过,一切都被删除,因此,例如,你不能分辨以下的事情:
scala> List(1, 2, 3).getClass == List("a", "b", "c").getClass
res1: Boolean = true
(如果现在还不清楚,我想类型擦除是明确一件好事,并与类型消除在JVM上唯一的问题是,它不是更完整。)
您可以写:
import scala.reflect.{ ClassTag, classTag }
class G1[A: ClassTag](val a: A) {
val c: A = classTag[A].runtimeClass.newInstance().asInstanceOf[A]
}
而且使用这样的:
scala> val stringG1: G1[String] = new G1("foo")
stringG1: G1[String] = [email protected]
scala> stringG1.c
res2: String = ""
这是一个非常糟糕的主意,不过,因为它会在运行时崩溃了许多许多类型参数:
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
更好的方法是通过构造函数:
class G1[A](val a: A)(empty:() => A) {
val c: A = empty()
}
而一个多更好的方法是使用类型类:
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
}
然后:
scala> val fooG1: G1[Foo] = new G1(new Foo(10101))
fooG1: G1[Foo] = [email protected]
scala> fooG1.c
res0: Foo = [email protected]
这里我们指的是A
在G1
定义,但我们只是参考已确认的属性和操作,或者在编译时可用。
它看起来像是因为编译器无法解决'A'是一个类。这个问题看起来相关:http://stackoverflow.com/questions/6200253/scala-classof-for-type-parameter(它使用'classOf'而不是'new',但原理是相同的,我认为) –
并且更一般地回答你的要点,是的,类型参数可以出现在函数体中,当你需要一个类型时声明返回类型等等,但是你在代码中要求更多:类型被用作类。 –