Quero obter o tipo de variável em tempo de execução. Como eu faço isso?
fonte
Quero obter o tipo de variável em tempo de execução. Como eu faço isso?
Portanto, estritamente falando, o "tipo de variável" está sempre presente e pode ser passado como um parâmetro de tipo. Por exemplo:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
Mas, dependendo do que você deseja fazer , isso não o ajudará. Por exemplo, pode querer não saber qual é o tipo da variável, mas saber se o tipo do valor é algum tipo específico, como este:
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
Aqui não importa qual é o tipo da variável Any
,. O que importa, o que é verificado é o tipo 5
, o valor. Na verdade, T
é inútil - você poderia muito bem tê-lo escrito def f(v: Any)
. Além disso, ele usa um ClassTag
ou um valor Class
, que são explicados abaixo, e não pode verificar os parâmetros de tipo de um tipo: você pode verificar se algo é um List[_]
( List
de algo), mas não se é, por exemplo, um List[Int]
ou List[String]
.
Outra possibilidade é que você queira reificar o tipo da variável. Ou seja, você deseja converter o tipo em um valor, para que possa armazená-lo, distribuí-lo etc. Isso envolve reflexão e você usará um ClassTag
ou um TypeTag
. Por exemplo:
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
também permitirá que você use os parâmetros de tipo recebidos em match
. Isso não vai funcionar:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
Mas isso vai:
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)
Aqui estou usando a sintaxe de limites de contexto,,B : ClassTag
que funciona exatamente como o parâmetro implícito no ClassTag
exemplo anterior , mas usa uma variável anônima.
Também se pode obter um ClassTag
de um valor Class
, como este:
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
é limitado por cobrir apenas a classe base, mas não seus parâmetros de tipo. Ou seja, o ClassTag
para List[Int]
e List[String]
é o mesmo List
,. Se você precisar de parâmetros de tipo, deverá usar um TypeTag
. No TypeTag
entanto, A não pode ser obtido de um valor, nem pode ser usado em uma correspondência de padrão, devido ao apagamento da JVM .
Exemplos com TypeTag
podem ser bastante complexos - nem mesmo comparar duas tags de tipo não é exatamente simples, como pode ser visto abaixo:
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
Claro, há maneiras de fazer essa comparação retornar verdadeira, mas seriam necessários alguns capítulos de livro para realmente cobrir TypeTag
, então vou parar por aqui.
Finalmente, talvez você não se importe com o tipo de variável. Talvez você apenas queira saber qual é a classe de um valor, caso em que a resposta é bastante simples:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
Seria melhor, entretanto, ser mais específico sobre o que você deseja realizar, para que a resposta seja mais precisa.
5
é uma instância deInt
e uma instância deAny
. Tirando isso, sua explicação foi perfeita :)Int
éAny
, masAny
não éInt
. Funciona no Scala 2.10 e deveria funcionar no Scala 2.11, e não sei por que não.a match { case _: B => ...
testa o tipo do valor real da variávela
, não o tipo da variávela
. Você está certo ao dizer que ele retorna o que você disse em scala 2.10.6. Mas deve ser um bug. No scala 2.11.8, o tipo do valor real é testado, como deveria.Eu acho que a questão está incompleta. se você quis dizer que deseja obter as informações de tipo de alguma typeclass, a seguir:
Se você deseja imprimir conforme especificou:
Se você estiver no modo repl, então
Ou se você apenas deseja saber qual é o tipo de classe, então como @monkjack explica
"string".getClass
pode resolver o propósitofonte
typeof x
, aquimanOf(x)
diga o tipo de dados!Se por tipo de variável você quer dizer a classe de tempo de execução do objeto para o qual a variável aponta, você pode obter isso por meio da referência de classe que todos os objetos têm.
Se você, entretanto, quer dizer o tipo com o qual a variável foi declarada, você não pode obter isso. Por exemplo, se você diz
então você ainda terá um
String
retorno do código acima.fonte
name.getClass.getSimpleName
para obter uma saída mais legíveleu testei isso e funcionou
fonte