L'esecuzione di questo esempio, l'interprete Scala con avvisi incontrollati su (scala -unchecked
) produce il seguente avviso: warning: refinement AnyRef{def doesNotExist(Int,List[_]): Double} in type pattern is unchecked since it is eliminated by erasure
. Sfortunatamente, un tipo generico come questo non può essere verificato in fase di esecuzione poiché la JVM non ha generici reificati.
Tutto ciò che la JVM vede in questa partita modello è:
"hello" match {
case s: Object => ...
case annon: Object => ...
}
EDIT: In risposta ai vostri commenti, ho pensato a una soluzione, ma non ha avuto il tempo di postare ieri . Sfortunatamente, anche se dovrebbe funzionare, il compilatore non riesce a iniettare l'appropriato Manifest
.
Il problema che si desidera risolvere è confrontare se un oggetto è di un determinato tipo strutturale. Ecco un po 'di codice che ho pensato di (Scala 2,8-r20019, come Scala 2.7.6.final si è schiantato su di me un paio di volte durante il gioco con idee simili)
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]
Metodo isFoo
confronta fondamentalmente i manifesti delle classe x
di Foo
. In un mondo ideale, il manifest di un tipo strutturale dovrebbe essere uguale al manifest di qualsiasi tipo contenente i metodi richiesti. Almeno questo è il mio pensiero. Sfortunatamente questo non riesce a compilare, poiché il compilatore inietta un Manifest[AnyRef]
invece di un Manifest[Foo]
quando chiama getManifest[Foo]
. È interessante notare che, se non si utilizza un tipo strutturale (ad esempio, type Foo = String
), questo codice viene compilato e funziona come previsto. A un certo punto pubblicherò una domanda per capire perché questo fallisce con i tipi strutturali - è una decisione di progettazione, o è solo un problema dell'API di riflessione sperimentale.
In caso contrario, è possibile utilizzare sempre il riflesso Java per verificare se un oggetto contiene un metodo.
def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {
try {
x.getClass.getMethod(name, params: _*)
true
}
catch {
case _ => false
}
}
che funziona come previsto:
containsMethod("foo", "concat", classOf[String]) // true
containsMethod("foo", "bar", classOf[List[Int]]) // false
... ma non è molto bello.
Inoltre, si noti che la struttura di un tipo strutturale non è disponibile in fase di esecuzione. Se si dispone di un metodo def foo(x: {def foo: Int}) = x.foo
, dopo la cancellazione si ottiene def foo(x: Object) = [some reflection invoking foo on x]
, le informazioni sul tipo vanno perse. Ecco perché il reflection viene utilizzato in primo luogo, poiché devi invocare un metodo su un Object
e la JVM non sa se lo Object
ha quel metodo.
ho ampliato la mia risposta alla luce del tuo commento :). –