Функция Scala, которая извлекает Class[_] из общего
Итак, что я хочу сделать:
def foo(clazz: Class[_]): Unit = {
val int = classOf[Int]
val str = classOf[String]
val opt = classOf[Option[_]]
clazz match {
case `int` => println("INT!")
case `str` => println("STRING!")
case `opt` => foo(clazz.getTheTypeOutOfGeneric) // <- I think you get the idea
}
}
Для данного clazz: Class[_ :< Option[_]]
Я хотел бы найти тип, с которым он был создан, так что в конце я бы получил INT!
при работе с типом Option[Int]
, Как мне это сделать? Нужно ли использовать отражения?
2 ответа
Проще говоря: Class
не несет никакой информации о параметрах типа.
Так например
classOf[Option[Int]] eq classOf[Option[String]]
вернусь true
, Обратите внимание, что оператор eq
проверяет ссылочное равенство, поэтому эти два объекта на самом деле являются одним и тем же объектом
Даже с размышлениями вы не сможете получить информацию, которой просто нет.
Я бы порекомендовал отойти от использования Class
значения и вместо этого использовать параметры типа и классы типов для специального полиморфизма. Точное решение зависит от того, что вы действительно пытаетесь сделать.
Но вот пример того, как работают классы типов:
def get[F[_], A](a: F[A])(implicit ex: Extractor[A]): Unit = ex.extract
trait Extractor[A] {
def extract: Unit
}
implicit val intExtractor = new Extractor[Int] {
def extract: Unit = println("I am doing something for Int!")
}
implicit val strExtractor = new Extractor[String] {
def extract: Unit = println("I am doing something for String!")
}
val a = Some(1)
get(a)
Выход:
I am doing something for Int!
Для получения дополнительной информации я бы порекомендовал прочитать "Руководство астронавта Type Shapeless", которое (помимо обучения вас о Shapeless) поможет вам понять более общие аспекты универсального программирования в Scala.
Надеюсь, это поможет.
Вы не можете эту информацию от Class
из-за стирания типа. Вам понадобится ClassTag
для этого:
import scala.reflect.runtime.universe._
def foo[T : TypeTag](clazz: Class[T]) = clazz match {
...
case `opt` => foo(typeOf[T].typeArgs.head)
...
}
Но прежде чем сделать это, проверьте Type
а также TypeTag
и другие вкусности в scala.reflect.runtime.universe
- Скорее всего, вы найдете более простой и элегантный способ реализовать то, что вам нужно, с помощью этого материала, чем передать сырье Class
вокруг.