它已經一段時間,因爲我經歷了Scala的源代碼在尋求回答同樣的問題......但簡短的回答挖,我記得 -
清單是個騙子代碼,讓編譯器繞過類型擦除(它不是在運行時使用)。它會在編譯時爲匹配清單的可能輸入類型生成多個代碼路徑。
Manifest是隱式解析的,但是如果在編譯時有關Manifest類型的含義有任何歧義,編譯器將停止。
隨着Manifest
的副本,你有幾件事情可用。您通常希望主要的事情是,要麼經erasure
擦除java.lang.Class
:
class BoundedManifest[T <: Any : Manifest](value: T) {
val m = manifest[T]
m.erasure.toString match {
case "class java.lang.String" => println("String")
case "double" | "int" => println("Numeric value.")
case x => println("WTF is a '%s'?".format(x))
}
}
class ImplicitManifest[T <: Any](value: T)(implicit m: Manifest[T]) {
m.erasure.toString match {
case "class java.lang.String" => println("String")
case "double" | "int" => println("Numeric value.")
case x => println("WTF is a '%s'?".format(x))
}
}
new BoundedManifest("Foo Bar!")
// String
new BoundedManifest(5)
// Numeric value.
new BoundedManifest(5.2)
// Numeric value.
new BoundedManifest(BigDecimal("8.62234525"))
// WTF is a 'class scala.math.BigDecimal'?
new ImplicitManifest("Foo Bar!")
// String
new ImplicitManifest(5)
// Numeric value.
new ImplicitManifest(5.2)
// Numeric value.
new ImplicitManifest(BigDecimal("8.62234525"))
// WTF is a 'class scala.math.BigDecimal'?
這是一個相當靠不住的例子,但說明是怎麼回事。我在Scala 2.8上運行該輸出以及FWIW。
[T ... : Manifest]
邊界在Scala 2.8中是新的......你以前必須隱式地抓取清單,如ImplicitManifest
所示。你實際上並沒有獲得Manifest的副本。但是,您可以通過說val m = manifest[T]
... manifest[_]
在Predef
上定義,並且可以在限制塊內找到正確的清單類型,從而在代碼中獲取一個。
您從Manifest
獲得的另外兩個主要項目是<:<
和>:>
,它測試一個清單的子類型/超類型與另一個清單。如果我正確記得這些是非常天真的執行方式,並不總是匹配,但我有一堆生產代碼使用它們來測試一些可能的擦除輸入。
class BoundedManifestCheck[T <: Any : Manifest](value: T) {
val m = manifest[T]
if (m <:< manifest[AnyVal]) {
println("AnyVal (primitive)")
} else if (m <:< manifest[AnyRef]) {
println("AnyRef")
} else {
println("Not sure what the base type of manifest '%s' is.".format(m.erasure))
}
}
new BoundedManifestCheck("Foo Bar!")
// AnyRef
new BoundedManifestCheck(5)
// AnyVal (primitive)
new BoundedManifestCheck(5.2)
// AnyVal (primitive)
new BoundedManifestCheck(BigDecimal("8.62234525"))
// AnyRef
豪爾赫·奧爾蒂斯有一個偉大的博客文章(雖然是舊)本:http://www.scala-blogs.org/2008/10/manifests-reified-types.html
編輯:對另一清單檢查的一個簡單的例子
實際上,你可以看到Scala是什麼通過要求它打印出擦除編譯器階段的結果。
運行,在我的最後一個例子以上scala -Xprint:erasure test.scala
產生以下結果:?什麼是Scala中的一個清單,當你需要它]的
final class Main extends java.lang.Object with ScalaObject {
def this(): object Main = {
Main.super.this();
()
};
def main(argv: Array[java.lang.String]): Unit = {
val args: Array[java.lang.String] = argv;
{
final class $anon extends java.lang.Object {
def this(): anonymous class $anon = {
$anon.super.this();
()
};
class BoundedManifestCheck extends java.lang.Object with ScalaObject {
<paramaccessor> private[this] val value: java.lang.Object = _;
implicit <paramaccessor> private[this] val evidence$1: scala.reflect.Manifest = _;
def this($outer: anonymous class $anon, value: java.lang.Object, evidence$1: scala.reflect.Manifest): BoundedManifestCheck = {
BoundedManifestCheck.super.this();
()
};
private[this] val m: scala.reflect.Manifest = scala.this.Predef.manifest(BoundedManifestCheck.this.evidence$1);
<stable> <accessor> def m(): scala.reflect.Manifest = BoundedManifestCheck.this.m;
if (BoundedManifestCheck.this.m().<:<(scala.this.Predef.manifest(reflect.this.Manifest.AnyVal())))
scala.this.Predef.println("AnyVal (primitive)")
else
if (BoundedManifestCheck.this.m().<:<(scala.this.Predef.manifest(reflect.this.Manifest.Object())))
scala.this.Predef.println("AnyRef")
else
scala.this.Predef.println(scala.this.Predef.augmentString("Not sure what the base type of manifest '%s' is.").format(scala.this.Predef.genericWrapArray(Array[java.lang.Object]{BoundedManifestCheck.this.m().erasure()})));
protected <synthetic> <paramaccessor> val $outer: anonymous class $anon = _;
<synthetic> <stable> def Main$$anon$BoundedManifestCheck$$$outer(): anonymous class $anon = BoundedManifestCheck.this.$outer
};
new BoundedManifestCheck($anon.this, "Foo Bar!", reflect.this.Manifest.classType(classOf[java.lang.String]));
new BoundedManifestCheck($anon.this, scala.Int.box(5), reflect.this.Manifest.Int());
new BoundedManifestCheck($anon.this, scala.Double.box(5.2), reflect.this.Manifest.Double());
new BoundedManifestCheck($anon.this, scala.package.BigDecimal().apply("8.62234525"), reflect.this.Manifest.classType(classOf[scala.math.BigDecimal]))
};
{
new anonymous class $anon();
()
}
}
}
}
可能重複(http://stackoverflow.com/問題/ 3213510 /什麼是一個清單在scala和什麼時候你需要它) – 2010-08-27 19:38:35
我不確定那些答案真的回答它的工作原理,但?至少它可以更清楚。編譯器爲方法/函數添加一個額外參數以保存泛型參數的具體類的意義何在?無論如何,<:<運算符是什麼? – djc 2010-08-27 19:42:55
看看這裏:http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html – 2010-08-27 19:47:31