ejecutar este ejemplo en el intérprete Scala con advertencias sin marcar en (scala -unchecked
) produce la siguiente advertencia: warning: refinement AnyRef{def doesNotExist(Int,List[_]): Double} in type pattern is unchecked since it is eliminated by erasure
. Desafortunadamente, un tipo genérico como este no se puede verificar en tiempo de ejecución ya que la JVM no tiene genéricos reificados.
Todo lo que el JVM ve en esta coincidencia de patrón es:
"hello" match {
case s: Object => ...
case annon: Object => ...
}
EDIT: En respuesta a sus comentarios, he estado pensando en una solución, pero no tienen el tiempo para publicar ayer . Desafortunadamente, incluso si funciona, el compilador no puede inyectar el Manifest
adecuado.
El problema que desea resolver es comparar si un objeto es de un tipo estructural dado. Aquí hay un código que he estado pensando en Scala (2,8-r20019, como Scala 2.7.6.final estrellado sobre mí un par de veces mientras jugaba con ideas similares)
type Foo = AnyRef { def doesNotExist(i: Int, x: List[_]): Double }
def getManifest[T](implicit m: Manifest[T]) = m
def isFoo[T](x: T)(implicit mt: Manifest[T]) =
mt == getManifest[Foo]
Método isFoo
básicamente compara los manifiestos de la clase x
de Foo
. En un mundo ideal, el manifiesto de un tipo estructural debe ser igual al manifiesto de cualquier tipo que contenga los métodos requeridos. Al menos esa es mi línea de pensamiento. Lamentablemente, esto no se puede compilar, ya que el compilador inyecta un Manifest[AnyRef]
en lugar de un Manifest[Foo]
al llamar al getManifest[Foo]
. Curiosamente, si no usa un tipo estructural (por ejemplo, type Foo = String
), este código se compila y funciona como se espera. En algún momento, publicaré una pregunta para ver por qué esto falla con los tipos estructurales: ¿es una decisión de diseño o es solo un problema de la API de reflexión experimental?
De lo contrario, siempre se puede usar la reflexión de Java para ver si un objeto contiene un método.
def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {
try {
x.getClass.getMethod(name, params: _*)
true
}
catch {
case _ => false
}
}
que funciona como se esperaba:
containsMethod("foo", "concat", classOf[String]) // true
containsMethod("foo", "bar", classOf[List[Int]]) // false
... pero no es muy agradable.
Además, tenga en cuenta que la estructura de un tipo estructural no está disponible en tiempo de ejecución. Si tiene un método def foo(x: {def foo: Int}) = x.foo
, después del borrado obtiene def foo(x: Object) = [some reflection invoking foo on x]
, y se pierde la información del tipo. Es por eso que se usa la reflexión en primer lugar, ya que debe invocar un método en un Object
y la JVM no sabe si el Object
tiene ese método.
he ampliado mi respuesta a la luz de su comentario :). –