Respostas:
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.
Int
é Any
, mas Any
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ável a
, não o tipo da variável a
. 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:
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]
Se você estiver no modo repl, então
scala> :type List(1,2,3)
List[Int]
Ou se você apenas deseja saber qual é o tipo de classe, então como @monkjack explica "string".getClass
pode resolver o propósito
typeof x
, aqui manOf(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.
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
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
val name: Object = "sam"
então você ainda terá um String
retorno do código acima.
name.getClass.getSimpleName
para obter uma saída mais legível
eu testei isso e funcionou
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5
é uma instância deInt
e uma instância deAny
. Tirando isso, sua explicação foi perfeita :)