是的,你說得對,這是因爲擦除 - 你不知道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',但原理是相同的,我認爲) –
並且更一般地回答你的要點,是的,類型參數可以出現在函數體中,當你需要一個類型時聲明返回類型等等,但是你在代碼中要求更多:類型被用作類。 –