Uruchomienie tego przykład w tłumacza Scala z niekontrolowanych ostrzeżeń na (scala -unchecked
) wywołuje następujące ostrzeżenie: warning: refinement AnyRef{def doesNotExist(Int,List[_]): Double} in type pattern is unchecked since it is eliminated by erasure
. Niestety typowy typ taki jak ten nie może być sprawdzony w czasie wykonywania, ponieważ JVM nie ma reifikowanych generycznych.
Wszystko to JVM widzi w tym meczu jest wzór:
"hello" match {
case s: Object => ...
case annon: Object => ...
}
EDIT: W odpowiedzi na komentarze, myślałem o rozwiązanie, ale nie mają czasu, aby opublikować go wczoraj . Niestety, nawet jeśli działa powinien działać, kompilator nie wstrzykuje odpowiedniego Manifest
.
Problem, który chcesz rozwiązać, to porównanie, czy obiekt ma określony typ konstrukcyjny. Oto niektóre kodu Myślałam o Scala (2,8 r20019, jak Scala 2.7.6.final rozbił się na mnie kilka razy podczas gry z podobnych pomysłów)
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]
Method isFoo
zasadzie porównuje manifesty klasa x
z Foo
. W idealnym świecie manifest typu strukturalnego powinien być równy manifestowi dowolnego typu zawierającego wymagane metody. Przynajmniej to mój ciąg myśli. Niestety, ta kompilacja nie powiedzie się, ponieważ kompilator wstrzykuje Manifest[AnyRef]
zamiast Manifest[Foo]
podczas wywoływania getManifest[Foo]
. Co ciekawe, jeśli nie używasz typu strukturalnego (na przykład type Foo = String
), ten kod kompiluje się i działa zgodnie z oczekiwaniami. W pewnym momencie opublikuję pytanie, aby zobaczyć, dlaczego to się nie udaje z typami strukturalnymi - jest to decyzja projektowa lub jest to tylko problem eksperymentalnego interfejsu API do refleksji.
W przeciwnym razie zawsze można użyć refleksji Java, aby sprawdzić, czy obiekt zawiera metodę.
def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {
try {
x.getClass.getMethod(name, params: _*)
true
}
catch {
case _ => false
}
}
który działa zgodnie z oczekiwaniami:
containsMethod("foo", "concat", classOf[String]) // true
containsMethod("foo", "bar", classOf[List[Int]]) // false
... ale to nie jest bardzo miłe.
Należy również zauważyć, że struktura typu strukturalnego nie jest dostępna w środowisku wykonawczym. Jeśli masz metodę def foo(x: {def foo: Int}) = x.foo
, po usunięciu otrzymujesz def foo(x: Object) = [some reflection invoking foo on x]
, informacja o typie jest tracona. Właśnie dlatego odbicie jest używane w pierwszej kolejności, ponieważ musisz wywołać metodę na Object
, a JVM nie wie, czy ta metoda ma wartość Object
.
I Rozszerzyliśmy moją odpowiedź w świetle Twojego komentarza :). –