Я хочу получить тип переменной во время выполнения
Я хочу получить тип переменной во время выполнения. Как мне это сделать?
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
чего-то), но не является ли это, например, aList[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
назад из приведенного выше кода.