Voglio ottenere il tipo di una variabile in fase di esecuzione

Voglio ottenere il tipo di una variabile in fase di esecuzione. Come faccio a fare questo?

Quindi, in senso stretto, il “tipo di una variabile” è sempre presente e può essere passato in giro come parametro di tipo. Per esempio:

val x = 5 def f[T](v: T) = v f(x) // T is Int, the type of x 

Ma a seconda di cosa vuoi fare , questo non ti aiuterà. Ad esempio, potrebbe voler non sapere qual è il tipo di variabile, ma sapere se il tipo del valore è un tipo specifico, come questo:

 val x: Any = 5 def f[T](v: T) = v match { case _: Int => "Int" case _: String => "String" case _ => "Unknown" } f(x) 

Qui non importa quale sia il tipo di variabile, Any . Ciò che conta, ciò che viene controllato è il tipo di 5 , il valore. In realtà, T è inutile – potresti anche averlo scritto def f(v: Any) . Inoltre, utilizza ClassTag o la Class un valore, illustrata di seguito, e non può controllare i parametri di tipo di un tipo: puoi verificare se qualcosa è un List[_] ( List di qualcosa), ma non se lo è, per esempio, un List[Int] o List[String] .

Un’altra possibilità è che si voglia reificare il tipo di variabile. Cioè, vuoi convertire il tipo in un valore, in modo da poterlo archiviare, passarlo, ecc. Ciò implica la riflessione e utilizzerai ClassTag o TypeTag . Per esempio:

 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" 

Un ClassTag ti consente anche di usare i parametri di tipo che hai ricevuto sulla match . Questo non funzionerà:

 def f[A, B](a: A, b: B) = a match { case _: B => "A is a B" case _ => "A is not a B" } 

Ma questo:

 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) 

Qui sto usando la syntax dei limiti di contesto , B : ClassTag , che funziona proprio come il parametro implicito nell’esempio ClassTag precedente, ma utilizza una variabile anonima.

Si può anche ottenere un ClassTag dalla ClassTag di un valore, come questo:

 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 

Un ClassTag è limitato in quanto copre solo la class base, ma non i suoi parametri tipo. Cioè, il ClassTag per List[Int] e List[String] è lo stesso, List . Se hai bisogno di parametri di tipo, devi invece usare un TypeTag . Tuttavia, un TypeTag non può essere ottenuto da un valore, né può essere utilizzato su una corrispondenza di pattern, a causa della cancellazione di JVM.

Gli esempi con TypeTag possono diventare piuttosto complessi – nemmeno il confronto tra due tag di tipo non è esattamente semplice, come si può vedere di seguito:

 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 

Certo, ci sono modi per rendere il paragone vero, ma richiederebbe alcuni capitoli di libri per coprire veramente il TypeTag , quindi mi fermerò qui.

Infine, forse non ti interessa affatto il tipo di variabile. Forse vuoi solo sapere qual è la class di un valore, nel qual caso la risposta è piuttosto semplice:

 val x = 5 x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it 

Sarebbe meglio, tuttavia, essere più specifici su ciò che si vuole realizzare, in modo che la risposta possa essere più pertinente.

Penso che la domanda sia incompleta. se volevi dire che desideri ottenere le informazioni sul tipo di alcuni tipi di disco allora in basso:

Se desideri stampare come hai specificato, procedi nel seguente modo:

 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 sei in modalità repl allora

 scala> :type List(1,2,3) List[Int] 

O se vuoi solo sapere che tipo di class allora come @monkjack spiega "string".getClass potrebbe risolvere lo scopo

Se per il tipo di variabile si intende la class runtime dell’object a cui punta la variabile, è ansible ottenere ciò attraverso il riferimento alla class che tutti gli oggetti hanno.

 val name = "sam"; name: java.lang.String = sam name.getClass res0: java.lang.Class[_] = class java.lang.String 

Se si intende comunque il tipo di dichiarazione della variabile, non è ansible ottenerlo. Ad esempio, se dici

 val name: Object = "sam" 

quindi otterrai ancora una String dal codice precedente.

l’ho provato e ha funzionato

 val x = 9 def printType[T](x:T) :Unit = {println(x.getClass.toString())}