Предоставление объекта Class с верхней привязкой типа с помощью classManifest

Допустим, мне нужно предоставить методу объект java.lang.Class, представляющий подкласс некоторого родительского класса A. Мне нужно сделать это из другого метода, который имеет общий параметр с верхним типом, привязанным к A.

Я подумал, что это может сработать:

class A
def f(clazz: java.lang.Class[_ <: A]) = ()
def g[T <: A : Manifest] = f(classManifest[T].erasure)

Но это не так:

<console>:9: error: type mismatch;
 found   : java.lang.Class[_$1(in method g)] where type _$1(in method g)
 required: java.lang.Class[_ <: A]
         def g[T <: A : Manifest] = f(classManifest[T].erasure)
                                                       ^

Почему компилятор не может понять, что T действительно является подклассом A? Я могу как-то помочь? Или я должен подойти к этому совершенно по-другому?


person Nicolas Payette    schedule 06.07.2012    source источник


Ответы (1)


Это не работает, потому что erasure имеет тип Class[_], который является экзистенциальным типом. Это означает, что Class объект erasure параметризован каким-то типом, но не важно, какой именно это тип. erasure не имеет типа Class[T] выше.

Метод f ожидает параметр типа Class[_ <: A], который является некоторым известным типом, являющимся подтипом A. Эта верхняя граница не обязательно обеспечивается указанным выше типом Class[_].

Решение: вы знаете, что erasure имеет правильный тип, просто этот тип не отображается в объекте ClassManifest. Просто произнесите это:

classManifest[T].erasure.asInstanceOf[Class[A]]

РЕДАКТИРОВАТЬ:

Если у вас есть подкласс B из A:

scala> class A

scala> def f(clazz: java.lang.Class[_ <: A]) = ()

scala> def g[T <: A : Manifest] = f(classManifest[T].erasure.asInstanceOf[Class[A]])

scala> g[A]

scala> class B extends A

scala> g[B]
person axel22    schedule 06.07.2012
comment
Я принимаю ваш ответ, так как ваше объяснение правильное и ясное. Ваше решение, однако, не работает для меня, потому что мой реальный метод f действительно должен иметь объект Class для подтипа, а не для A. Мое собственное решение состояло в том, чтобы отказаться от использования дженериков и передать объект класса (полученный с помощью classOf) по всему пути вызова, то есть вызов g теперь выглядит так: g[SomeSubclass](classOf[SomeSubclass]). (Параметр типа по-прежнему необходим по причинам, не указанным выше.) - person Nicolas Payette; 06.07.2012
comment
Вы совершенно правы. Я был сбит с толку и не понял, что даже если вы преобразуете объект Class для B в качестве экземпляра Class[A], он остается объектом Class для B. Благодарю вас! - person Nicolas Payette; 10.07.2012