Подтвердить что ты не робот

Scala - получение объекта класса из общего типа

Можно ли создать объект класса исключительно из общего параметра? Например:

class myclass[T] { 
  def something(): Class[_ <: T] = 
    classOf[T] //this doesn't work
}

Так как тип будет удален во время выполнения, это похоже на работу для манифестаций, но я не нашел примера, демонстрирующего это конкретное использование. Я попробовал следующее, но он тоже не работает:

class myclass[T] { 
  def something()(implicit m: Manifest[T]): Class[_ <: T] = 
    m.erasure //this doesn't work
}

Я подозреваю, что этот сбой вызван тем, что, как указывает API, нет отношения подтипа между типом результата m.erasure и T.

EDIT: меня не интересует тип T, мне просто нужен объект типа Class[_ <: T] для перехода к методу в структуре hadoop.

Любые указатели?

4b9b3361

Ответ 1

Вы можете передать результат m.erasure в Class[T]:

class myclass[T] { 
    def something()(implicit m: Manifest[T]): Class[T] = 
        m.erasure.asInstanceOf[Class[T]]
}

Это отлично подходит для базовых (не общих) типов:

scala> new myclass[String]().something()
res5: Class[String] = class java.lang.String

Но обратите внимание, что произойдет, если я использую конструктор экземпляров типа List[String] для T:

scala> new myclass[List[String]]().something()
res6: Class[List[String]] = class scala.collection.immutable.List

Из-за стирания существует только один объект Class для всех возможных экземпляров данного конструктора типов.

Изменить

Я не уверен, почему Manifest[T].erasure возвращает Class[_] вместо Class[T], но если бы мне пришлось спекулировать, я бы сказал, что это препятствует вам использовать методы на Class, которые позволяют сравнивать два классы для равенства или отношения подтипа, так как эти методы дадут вам неправильные ответы, когда параметр Class параметризуется с помощью созданного типичного типа.

Например,

scala> classOf[List[String]] == classOf[List[Int]]
res25: Boolean = true

scala> classOf[List[String]].isAssignableFrom(classOf[List[Int]])
res26: Boolean = true

Эти результаты могут удивить вас и/или привести к ошибке в вашей программе. Вместо того, чтобы сравнивать классы таким образом, вы обычно должны просто обходить Manifest и сравнивать их, так как они имеют больше информации *:

scala> manifest[List[String]] == manifest[List[Int]]
res27: Boolean = false

scala> manifest[List[String]] >:> manifest[List[Int]]
res28: Boolean = false

Как я понимаю, Manifest предназначены для замены Class es для большинства случаев использования... но, конечно, если вы используете фреймворк, который требует Class, выбора не так много. Я бы предположил, что наложение результата erasure является всего лишь своего рода "признанием ответственности" за то, что вы используете худший продукт на свой страх и риск:)

* Обратите внимание, что, как сообщает документация для манифеста, эти явные операторы сравнения "должны рассматриваться только как аппроксимации, так как существует множество аспектов соответствия типов, которые не являются но адекватно представлены в манифесте".

Ответ 2

def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass

Ответ 3

.erasure предоставляет тип, к которому стирается ваш тип. Если вам нужна полная информация о типе, вы должны вернуть Manifest.

scala> class MyClass[A] {
     |   def stuff(implicit m: Manifest[A]): Class[_] = m.erasure
     | }
defined class MyClass

scala> new MyClass[Int].stuff
res551: java.lang.Class[_] = int

scala> new MyClass[List[Int]].stuff
res552: java.lang.Class[_] = class scala.collection.immutable.List

scala> class MyClass[A] {
     |   def stuff(implicit m: Manifest[A]): Manifest[A] = m
     | }
defined class MyClass

scala> new MyClass[Int].stuff
res553: Manifest[Int] = Int

scala> new MyClass[List[Int]].stuff
res554: Manifest[List[Int]] = scala.collection.immutable.List[Int]