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

Я хочу получить тип переменной во время выполнения

Я хочу получить тип переменной во время выполнения. Как это сделать?

4b9b3361

Ответ 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())}