Je veux obtenir le type d'une variable au moment de l'exécution. Comment puis-je faire cela?
la source
Je veux obtenir le type d'une variable au moment de l'exécution. Comment puis-je faire cela?
Donc, à proprement parler, le "type d'une variable" est toujours présent, et peut être passé en paramètre de type. Par exemple:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
Mais selon ce que vous voulez faire , cela ne vous aidera pas. Par exemple, vous voudrez peut-être ne pas savoir quel est le type de la variable, mais savoir si le type de la valeur est un type spécifique, tel que celui-ci:
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
Ici , il n'a pas d' importance quel est le type de la variable, Any
. Ce qui compte, c'est le type de 5
, la valeur qui est vérifié . En fait, T
c'est inutile - vous auriez aussi bien pu l'écrire à la def f(v: Any)
place. De plus, cela utilise soit ClassTag
ou une valeur Class
, qui sont expliquées ci-dessous, et ne peut pas vérifier les paramètres de type d'un type: vous pouvez vérifier si quelque chose est un List[_]
( List
de quelque chose), mais pas s'il s'agit, par exemple, d'un List[Int]
ou List[String]
.
Une autre possibilité est que vous souhaitiez réifier le type de la variable. Autrement dit, vous voulez convertir le type en une valeur, afin de pouvoir le stocker, le transmettre, etc. Cela implique une réflexion, et vous utiliserez l'un ClassTag
ou l' autre TypeTag
. Par exemple:
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 vous ClassTag
permettra également d'utiliser les paramètres de type que vous avez reçus match
. Cela ne fonctionnera pas:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
Mais cela va:
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)
Ici, j'utilise la syntaxe des limites de contexteB : ClassTag
, qui fonctionne comme le paramètre implicite de l' ClassTag
exemple précédent , mais utilise une variable anonyme.
On peut également obtenir un à ClassTag
partir d'une valeur Class
, comme ceci:
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 limité en ce qu'il ne couvre que la classe de base, mais pas ses paramètres de type. Autrement dit, le ClassTag
pour List[Int]
et List[String]
est le même List
,. Si vous avez besoin de paramètres de type, vous devez utiliser un à la TypeTag
place. TypeTag
Cependant, A ne peut pas être obtenu à partir d'une valeur, ni utilisé sur une correspondance de modèle, en raison de l' effacement de la JVM .
Les exemples avec TypeTag
peuvent devenir assez complexes - même pas comparer deux balises de type n'est pas exactement simple, comme on peut le voir ci-dessous:
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
Bien sûr, il existe des moyens de rendre cette comparaison vraie, mais il faudrait quelques chapitres de livre pour vraiment couvrir TypeTag
, alors je vais m'arrêter ici.
Enfin, peut-être que vous ne vous souciez pas du tout du type de variable. Peut-être voulez-vous simplement savoir quelle est la classe d'une valeur, auquel cas la réponse est assez simple:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
Il serait préférable, cependant, d'être plus précis sur ce que vous voulez accomplir, afin que la réponse soit plus précise.
5
est à la fois une instanceInt
et une instance deAny
. En dehors de cela, votre explication était parfaite :)Int
estAny
, maisAny
n'est pasInt
. Cela fonctionne sur Scala 2.10, et cela devrait fonctionner sur Scala 2.11, et je ne sais pas pourquoi ce n'est pas le cas.a match { case _: B => ...
teste le type de la valeur réelle de la variablea
, pas le type de la variablea
. Vous avez raison en ce qu'il renvoie ce que vous dites dans scala 2.10.6. Mais ça devrait être un bug. Dans scala 2.11.8, le type de la valeur réelle est testé, comme il se doit.Je pense que la question est incomplète. si vous vouliez dire que vous souhaitez obtenir les informations de type d'une classe de types, alors ci-dessous:
Si vous souhaitez imprimer comme vous l'avez spécifié, alors:
Si vous êtes en mode repl, alors
Ou si vous souhaitez simplement savoir quel type de classe, comme l'explique @monkjack, cela
"string".getClass
pourrait résoudre le problèmela source
typeof x
,manOf(x)
dites ici le type de données!Si par le type d'une variable vous entendez la classe d'exécution de l'objet vers lequel pointe la variable, vous pouvez l'obtenir via la référence de classe que tous les objets ont.
Si toutefois vous voulez dire le type sous lequel la variable a été déclarée, vous ne pouvez pas l'obtenir. Par exemple, si vous dites
alors vous obtiendrez toujours un
String
retour du code ci-dessus.la source
name.getClass.getSimpleName
pour une sortie plus lisiblej'ai testé ça et ça a marché
la source