Запуск примера в интерпретаторе Scala с непроверенным предупреждения о (scala -unchecked
) производит следующее предупреждение: warning: refinement AnyRef{def doesNotExist(Int,List[_]): Double} in type pattern is unchecked since it is eliminated by erasure
. К сожалению, общий тип, подобный этому, не может быть проверен во время выполнения, поскольку JVM не имеет повторных дженериков.
Все, что виртуальная машина видит в этом матче картина:
"hello" match {
case s: Object => ...
case annon: Object => ...
}
EDIT: В ответ на ваши комментарии, я думал о решении, но не было времени, чтобы разместить его вчера , К сожалению, даже если он должен работать, компилятор не может ввести надлежащее Manifest
.
Проблема, которую вы хотите решить, заключается в сравнении, если объект имеет определенный структурный тип. Вот код, который я думал о (Scala 2.8-r20019, а Scala 2.7.6.final упал на меня пару раз, играя с подобными идеями)
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]
Метод isFoo
в основном сравнивает манифестов класс x
от Foo
. В идеальном мире манифест структурного типа должен быть равен манифесту любого типа, содержащего требуемые методы. По крайней мере, это мой ход мысли. К сожалению, это не скомпилируется, поскольку компилятор вводит Manifest[AnyRef]
вместо Manifest[Foo]
при вызове getManifest[Foo]
. Интересно, что если вы не используете структурный тип (например, type Foo = String
), этот код компилируется и работает как ожидалось. В какой-то момент я поставил вопрос о том, почему это не удается со структурными типами - это дизайнерское решение, или это просто проблема API экспериментального отражения.
В противном случае вы всегда можете использовать отражение Java, чтобы увидеть, содержит ли объект метод.
def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {
try {
x.getClass.getMethod(name, params: _*)
true
}
catch {
case _ => false
}
}
, который работает, как ожидалось:
containsMethod("foo", "concat", classOf[String]) // true
containsMethod("foo", "bar", classOf[List[Int]]) // false
... но это не очень приятно.
Также обратите внимание, что структура структурного типа недоступна во время выполнения. Если у вас есть метод def foo(x: {def foo: Int}) = x.foo
, после удаления вы получаете def foo(x: Object) = [some reflection invoking foo on x]
, информация о типе теряется. Именно поэтому отражение используется в первую очередь, так как вы должны вызывать метод на Object
, а JVM не знает, имеет ли этот метод Object
.
Я расширил свой ответ в свете Вашего комментария :). –