L'exécution de cet exemple sur (scala -unchecked
) dans l'interpréteur Scala avec des avertissements non vérifiées produit l'avertissement suivant: warning: refinement AnyRef{def doesNotExist(Int,List[_]): Double} in type pattern is unchecked since it is eliminated by erasure
. Malheureusement, un type générique comme celui-ci ne peut pas être vérifié à l'exécution car la JVM n'a pas de génériques réifiés.
Tout ce que la machine virtuelle Java voit dans ce match de modèle est:
"hello" match {
case s: Object => ...
case annon: Object => ...
}
EDIT: En réponse à vos commentaires, j'ai pensé à une solution, mais n'a pas eu le temps de poster hier . Malheureusement, même si doit fonctionner, le compilateur n'injecte pas le bon Manifest
.
Le problème que vous voulez résoudre est de comparer si un objet est d'un type structurel donné. Voici un code que j'ai pensé (Scala 2.8-r20019, comme Scala 2.7.6.final écrasé sur moi deux ou trois fois tout en jouant avec des idées similaires)
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éthode isFoo
compare essentiellement les manifestes du classe x
de Foo
. Dans un monde idéal, le manifeste d'un type structurel doit être égal au manifeste de tout type contenant les méthodes requises. Au moins c'est mon train de pensée. Malheureusement, ceci échoue à compiler, car le compilateur injecte un Manifest[AnyRef]
au lieu d'un Manifest[Foo]
en appelant le getManifest[Foo]
. Fait intéressant, si vous n'utilisez pas un type structurel (par exemple, type Foo = String
), ce code compile et fonctionne comme prévu. Je vais poster une question à un moment donné pour voir pourquoi cela échoue avec les types structurels - est-ce une décision de conception, ou c'est juste un problème de l'API de réflexion expérimentale. A défaut, vous pouvez toujours utiliser la réflexion Java pour voir si un objet contient une méthode.
def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {
try {
x.getClass.getMethod(name, params: _*)
true
}
catch {
case _ => false
}
}
qui fonctionne comme prévu:
containsMethod("foo", "concat", classOf[String]) // true
containsMethod("foo", "bar", classOf[List[Int]]) // false
... mais ce n'est pas très agréable.
Notez également que la structure d'un type structurel n'est pas disponible au moment de l'exécution. Si vous avez une méthode def foo(x: {def foo: Int}) = x.foo
, après l'effacement vous obtenez def foo(x: Object) = [some reflection invoking foo on x]
, les informations de type étant perdues. C'est pourquoi la réflexion est utilisée en premier lieu, car vous devez invoquer une méthode sur un Object
et la JVM ne sait pas si le Object
a cette méthode.
J'ai développé ma réponse à la lumière de votre commentaire :). –