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


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

4 71

4 ответа:

таким образом, строго говоря, "тип переменной" всегда присутствует и может передаваться как параметр типа. Например:

val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x

но в зависимости от что ты хочешь do, это тебе не поможет. Например, может потребоваться не знать, что такое тип переменной, но знать, является ли тип стоимостью это какой-то конкретный тип, например:

val x: Any = 5
def f[T](v: T) = v match {
  case _: Int    => "Int"
  case _: String => "String"
  case _         => "Unknown"
}
f(x)

здесь не имеет значения, какой тип переменная, Any. Что имеет значение, то что проверяется это тип 5 значение. На самом деле,T бесполезно - вы могли бы также написать его . Кроме того, это использует ClassTag или значения Class, которые объясняются ниже, и не могут проверить параметры типа типа: вы можете проверить, является ли что-то List[_] (List чего-то), но не является ли это, например, a List[Int] или List[String].

другая возможность заключается в том, что вы хотите reify тип переменной. То есть вы хотите преобразовать тип в значение, чтобы вы могли его хранить, передавать и т. д. Это включает в себя отражение, и вы будете использовать либо 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 однако, не может может быть получен из значения, и он не может быть использован на соответствие шаблону, из-за 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

было бы лучше, однако, чтобы быть более конкретным о том, что вы хотите достичь, так, что ответ может быть более точным.

Я думаю, что вопрос является неполным. если вы имели в виду, что хотите получить информацию о типе некоторого класса, то ниже:

Если вы хотите напечатать, как вы указали, то:

scala>  def manOf[T: Manifest](t: T): Manifest[T] = manifest[T]
manOf: [T](t: T)(implicit evidence: 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 может решить цели

Если тип переменной вы имеете в виду класс времени выполнения объекта, на который указывает переменная, тогда вы можете получить это через ссылку на класс, которую имеют все объекты.

val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String

Если вы, однако, имеете в виду тип, который переменная была объявлена как, то вы не можете получить это. Например, если вы говорите

val name: Object = "sam"

тогда вы все равно получите String назад из приведенного выше кода.

Я проверил это, и это сработало

val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}