Ha sido un tiempo desde que abrí paso por el código fuente de Scala en un intento de responder a la misma pregunta ... pero la respuesta corta, por lo que recuerdo -
Manifiesto es un código de trucos para permitir que el compilador moverse por Tipo de borrado (no se usa en tiempo de ejecución). Hace que se generen varias rutas de código en tiempo de compilación para los posibles tipos de entrada que coincidan con el manifiesto.
El manifiesto se resuelve implícitamente, pero si hay alguna ambigüedad en tiempo de compilación sobre qué es el tipo manifiesto, el compilador se detendrá.
Con una copia de Manifest
tiene algunas cosas disponibles. Los elementos principales que normalmente desea es o bien la java.lang.Class
que fue borrado por medio de erasure
:
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'?
Este es un ejemplo bastante poco firme, pero muestra lo que está pasando. Lo ejecuté también para la salida FWIW en Scala 2.8.
El límite [T ... : Manifest]
es nuevo en Scala 2.8 ... solía tener que agarrar el manifiesto implícitamente como se muestra en ImplicitManifest
. En realidad, NO OBTIENE una copia del Manifiesto. Pero puede buscar uno dentro de su código diciendo val m = manifest[T]
... manifest[_]
se define en Predef
y demostrablemente encontrará el tipo de manifiesto adecuado dentro de un bloque delimitado.
Los otros dos elementos principales que obtienes de Manifest
es <:<
y >:>
que prueban el subtipo/supertipo de un manifiesto frente a otro. Si recuerdo correctamente, estas son MUY ingenuas en cuanto a la implementación y no siempre coinciden, pero tengo un montón de código de producción que las usa para probar contra algunas posibles entradas borradas.Un simple ejemplo de comprobación contra otro manifiesta:
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
Jorge Ortiz tiene una gran entrada en el blog (aunque de edad) en esto: http://www.scala-blogs.org/2008/10/manifests-reified-types.html
EDITAR:
se puede ver en realidad lo Scala es haciendo pidiéndole que imprima los resultados de la fase del compilador de borrado.
Correr, en mi último ejemplo anterior scala -Xprint:erasure test.scala
produce el siguiente resultado: [? ¿Qué es un manifiesto en Scala y cuando lo necesita]
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();
()
}
}
}
}
posible duplicado de (http://stackoverflow.com/ questions/3213510/what-is-a-manifest-in-scala-and-when-do-you-need-it) –
No estoy seguro de que esas respuestas realmente respondan cómo funciona, sin embargo? Por lo menos, podría ser más claro. ¿Es el punto que el compilador agrega un argumento adicional a los métodos/funciones para mantener la clase concreta para el parámetro genérico? ¿Y cuál es el operador <: <, de todos modos? – djc
Eche un vistazo aquí: http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html –