Я хочу получить тип переменной во время выполнения. Как мне это сделать?
источник
Я хочу получить тип переменной во время выполнения. Как мне это сделать?
Итак, строго говоря, «тип переменной» присутствует всегда и может передаваться как параметр типа. Например:
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
for List[Int]
и List[String]
то же самое List
,. Если вам нужны параметры типа, вы должны использовать TypeTag
вместо них. А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
Однако было бы лучше уточнить, чего вы хотите достичь, чтобы ответ был более конкретным.
5
является экземпляромInt
и экземпляромAny
. Кроме того, ваше объяснение было идеальным :)Int
естьAny
, ноAny
нетInt
. Он работает на Scala 2.10 и должен работать на Scala 2.11, и я не знаю, почему это не так.a match { case _: B => ...
проверяет тип фактического значения переменнойa
, а не тип переменнойa
. Вы правы в том, что он возвращает то, что вы говорите в scala 2.10.6. Но это должна быть ошибка. В scala 2.11.8 тип фактического значения тестируется, как и должно.Думаю, вопрос неполный. если вы имели в виду, что хотите получить информацию о типе некоторого класса типов, то ниже:
Если вы хотите печатать, как указали, тогда:
Если вы находитесь в режиме ответа, тогда
Или, если вы просто хотите знать, какой тип класса, как объясняет @monkjack,
"string".getClass
может решить цельисточник
typeof x
, здесьmanOf(x)
указывается тип данных!Если под типом переменной вы имеете в виду класс среды выполнения объекта, на который указывает переменная, то вы можете получить это через ссылку на класс, которая есть у всех объектов.
Однако если вы имеете в виду тип, в котором была объявлена переменная, вы не можете этого понять. Например, если вы скажете
тогда вы все равно получите
String
возврат из приведенного выше кода.источник
name.getClass.getSimpleName
для более читаемого выводая проверил это, и это сработало
источник