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



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

571   4  

4 ответов:

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

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)

Здесь я использую синтаксис context bounds , 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
Конечно, есть способы сделать это сравнение истинным, но для того, чтобы его действительно охватить, потребуется несколько глав книги, поэтому я остановлюсь здесь.

Наконец, возможно, вас вообще не волнует тип переменной. Может быть, вы просто хотите знать, что такое класс значения, и в этом случае ответ довольно прост:

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$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, может решить цель

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

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())}

Comments

    Ничего не найдено.