Я хочу получить тип переменной во время выполнения. Как это сделать?
Я хочу получить тип переменной во время выполнения
Ответ 1
Итак, строго говоря, "тип переменной" всегда присутствует и может быть передан как параметр типа. Например:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
Но в зависимости от того, что вы хотите сделать, это не поможет. Например, может не знать, что такое тип переменной, но знать, является ли тип значения определенным типом, например:
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
Здесь неважно, каков тип переменной, Any
. Важно, что проверяется тип 5
, значение. Фактически, T
бесполезен - вы могли бы написать вместо него def f(v: Any)
. Кроме того, это использует либо ClassTag
, либо значение Class
, которые объясняются ниже, и не могут проверять параметры типа типа: вы можете проверить, есть ли что-то List[_]
(List
чего-то), но не будь то, например, List[Int]
или List[String]
.
Другая возможность заключается в том, что вы хотите подтвердить тип переменной. То есть вы хотите преобразовать тип в значение, чтобы вы могли его сохранить, передать его и т.д. Это включает отражение, и вы будете использовать либо ClassTag
, либо TypeTag
. Например:
val x: Any = 5
import scala.reflect.ClassTag
def f[T](v: T)(implicit ev: ClassTag[T]) = ev.toString
f(x) // returns the string "Any"
A ClassTag
также позволит вам использовать параметры типа, полученные на match
. Это не сработает:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
Но это будет:
val x = 'c'
val y = 5
val z: Any = 5
import scala.reflect.ClassTag
def f[A, B: ClassTag](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
f(x, y) // A (Char) is not a B (Int)
f(x, z) // A (Char) is a B (Any)
Здесь я использую синтаксис границ контекста, B : ClassTag
, который работает так же, как неявный параметр в предыдущем примере ClassTag
, но использует анонимную переменную.
Можно также получить ClassTag
из значения Class
, например:
val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f(a: Any, b: Any) = {
val B = ClassTag(b.getClass)
ClassTag(a.getClass) match {
case B => "a is the same class as b"
case _ => "a is not the same class as b"
}
}
f(x, y) == f(y, x) // true, a is the same class as b
A ClassTag
ограничен тем, что он охватывает только базовый класс, но не его параметры типа. То есть, ClassTag
для List[Int]
и List[String]
- то же самое, List
. Если вам нужны параметры типа, то вместо этого вы должны использовать TypeTag
. Однако A TypeTag
не может быть получен из значения и не может использоваться для сопоставления шаблонов из-за стирания JVM.
Примеры с TypeTag
могут быть довольно сложными - даже сравнение двух тегов типа не совсем просто, как показано ниже:
import scala.reflect.runtime.universe.TypeTag
def f[A, B](a: A, b: B)(implicit evA: TypeTag[A], evB: TypeTag[B]) = evA == evB
type X = Int
val x: X = 5
val y = 5
f(x, y) // false, X is not the same type as Int
Конечно, есть способы сделать это сравнение верным, но для этого потребуется несколько глав книги, чтобы действительно покрыть TypeTag
, поэтому я остановлюсь здесь.
Наконец, может быть, вам вообще не нужен тип переменной. Возможно, вы просто хотите знать, что представляет собой класс значения, и в этом случае ответ довольно прост:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
Было бы лучше, однако, быть более конкретным о том, чего вы хотите достичь, чтобы ответ мог быть более точным.
Ответ 2
Я думаю, что вопрос неполный. если вы имели в виду, что хотите получить информацию о типе некоторого типа, ниже:
Если вы хотите напечатать, как вы указали, выполните следующие действия:
scala> def manOf[T: Manifest](t: T): Manifest[T] = manifest[T]
manOf: [T](t: T)(implicit evidence$1: Manifest[T])Manifest[T]
scala> val x = List(1,2,3)
x: List[Int] = List(1, 2, 3)
scala> println(manOf(x))
scala.collection.immutable.List[Int]
Если вы находитесь в режиме repl, то
scala> :type List(1,2,3)
List[Int]
Или, если вы просто хотите узнать, что тип класса, то как @monkjack объясняет, что "string".getClass
может решить цель
Ответ 3
Если по типу переменной вы подразумеваете класс времени выполнения объекта, на который указывает переменная, то вы можете получить это через ссылку на класс, которую имеют все объекты.
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
Если вы, однако, имеете в виду тип, который была объявлена переменной, тогда вы не сможете это получить. Например, если вы скажете
val name: Object = "sam"
то вы по-прежнему получите String
обратно из вышеуказанного кода.
Ответ 4
Я тестировал это, и он работал
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}