Respuestas:
Entonces, estrictamente hablando, el "tipo de una variable" siempre está presente y puede pasarse como un parámetro de tipo. Por ejemplo:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
Pero dependiendo de lo que quieras hacer , eso no te ayudará. Por ejemplo, es posible que no desee saber cuál es el tipo de variable, pero sí saber si el tipo de valor es un 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)
Aquí no importa cuál es el tipo de la variable, Any
. Lo que importa, lo que se comprueba es el tipo de 5
, el valor. De hecho, T
es inútil; bien podría haberlo escrito en su def f(v: Any)
lugar. Además, esto usa ClassTag
o un valor Class
, que se explica a continuación, y no puede verificar los parámetros de tipo de un tipo: puede verificar si algo es un List[_]
( List
de algo), pero no si es, por ejemplo, un List[Int]
o List[String]
.
Otra posibilidad es que desee cosificar el tipo de variable. Es decir, desea convertir el tipo en un valor, de modo que pueda almacenarlo, pasarlo, etc. Esto implica una reflexión y utilizará ClassTag
o bien a TypeTag
. Por ejemplo:
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
también le permitirá utilizar los parámetros de tipo que recibió match
. Esto no funcionará:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
Pero esto hará:
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)
Aquí estoy usando la sintaxis de límites de contextoB : ClassTag
, que funciona igual que el parámetro implícito en el ClassTag
ejemplo anterior , pero usa una variable anónima.
También se puede obtener un ClassTag
valor de 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
está limitado porque solo cubre la clase base, pero no sus parámetros de tipo. Es decir, el ClassTag
para List[Int]
y List[String]
es el mismo List
. Si necesita parámetros de tipo, debe usar un TypeTag
en su lugar. Sin TypeTag
embargo, no se puede obtener a partir de un valor, ni se puede utilizar en una coincidencia de patrón, debido al borrado de JVM .
Los ejemplos con TypeTag
pueden volverse bastante complejos; ni siquiera comparar dos etiquetas de tipo no es exactamente simple, como se puede ver a continuación:
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
Por supuesto, hay formas de hacer que esa comparación resulte verdadera, pero requeriría algunos capítulos de libro para cubrir realmente TypeTag
, así que me detendré aquí.
Finalmente, tal vez no le importe en absoluto el tipo de variable. Tal vez solo desee saber cuál es la clase de un valor, en cuyo caso la respuesta es bastante simple:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
Sin embargo, sería mejor ser más específico sobre lo que desea lograr, para que la respuesta sea más precisa.
Int
es Any
, pero Any
no es Int
. Funciona en Scala 2.10 y debería funcionar en Scala 2.11, y no sé por qué no lo es.
a match { case _: B => ...
prueba el tipo del valor real de la variable a
, no el tipo de la variable a
. Tiene razón en que devuelve lo que dice en scala 2.10.6. Pero debería ser un error. En scala 2.11.8 se prueba el tipo de valor real, como debería.
Creo que la pregunta está incompleta. si quiso decir que desea obtener la información de tipo de alguna clase de tipo, a continuación:
Si desea imprimir como ha especificado, entonces:
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]
Si está en modo de respuesta,
scala> :type List(1,2,3)
List[Int]
O si solo desea saber cuál es el tipo de clase, como explica @monkjack, "string".getClass
podría resolver el propósito
typeof x
, aquí manOf(x)
diga el tipo de datos.
Si por tipo de variable te refieres a la clase de tiempo de ejecución del objeto al que apunta la variable, entonces puedes obtenerla a través de la referencia de clase que tienen todos los objetos.
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
Sin embargo, si se refiere al tipo con el que se declaró la variable, no puede obtenerlo. Por ejemplo, si dices
val name: Object = "sam"
entonces aún obtendrá una String
devolución del código anterior.
name.getClass.getSimpleName
para una salida más legible
lo he probado y funcionó
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5
es una instancia deInt
y una instancia deAny
. Aparte de eso, su explicación fue perfecta :)