Risposte:
Quindi, in senso stretto, il "tipo di variabile" è sempre presente e può essere passato 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, potresti voler non sapere qual è il tipo di variabile, ma sapere se il tipo di 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 5
, il valore. In effetti, T
è inutile: potresti anche averlo scritto def f(v: Any)
invece. Inoltre, questo utilizza uno ClassTag
o un valore Class
, che viene spiegato di seguito, e non può controllare i parametri di tipo di un tipo: puoi controllare se qualcosa è a List[_]
( List
di qualcosa), ma non se è, ad esempio, a List[Int]
o List[String]
.
Un'altra possibilità è che tu voglia reificare il tipo di variabile. Cioè, vuoi convertire il tipo in un valore, in modo da poterlo memorizzare, passarlo, ecc. Ciò implica la riflessione e utilizzerai o ClassTag
o un file 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"
A ClassTag
ti consente anche di utilizzare i parametri di tipo ricevuti 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 sintassi dei limiti di contestoB : ClassTag
, che funziona proprio come il parametro implicito nell'esempio precedente ClassTag
, ma utilizza una variabile anonima.
Si può anche ottenere un ClassTag
da un valore Class
, 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
A ClassTag
è limitato in quanto copre solo la classe base, ma non i suoi parametri di tipo. Cioè, il ClassTag
per List[Int]
e List[String]
è lo stesso List
,. Se hai bisogno di parametri di tipo, devi usare TypeTag
invece un file . A TypeTag
, tuttavia, non può essere ottenuto da un valore, né può essere utilizzato su un pattern match, a causa della cancellazione di JVM .
Gli esempi con TypeTag
possono diventare piuttosto complessi - nemmeno confrontare 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
Ovviamente, ci sono modi per rendere vero questo confronto, ma richiederebbe alcuni capitoli di libro per coprire davvero TypeTag
, quindi mi fermo qui.
Infine, forse non ti interessa affatto il tipo di variabile. Forse vuoi solo sapere qual è la classe 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ù specifico su ciò che si desidera ottenere, in modo che la risposta possa essere più pertinente.
Int
è Any
, ma Any
non lo è Int
. Funziona su Scala 2.10 e dovrebbe funzionare su Scala 2.11, e non so perché non lo sia.
a match { case _: B => ...
verifica il tipo del valore effettivo della variabile a
, non il tipo della variabile a
. Hai ragione in quanto restituisce ciò che dici in scala 2.10.6. Ma dovrebbe essere un bug. In scala 2.11.8 viene testato il tipo del valore effettivo, come dovrebbe.
Penso che la domanda sia incompleta. se intendevi che desideri ottenere le informazioni sul tipo di qualche tipo di classe, allora di seguito:
Se desideri stampare come da te specificato, allora:
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à di sostituzione, allora
scala> :type List(1,2,3)
List[Int]
O se desideri solo sapere quale tipo di classe, come spiega @monkjack, "string".getClass
potrebbe risolvere lo scopo
typeof x
, qui manOf(x)
dì il tipo di dati!
Se per tipo di variabile si intende la classe di runtime dell'oggetto a cui punta la variabile, è possibile ottenerla tramite il riferimento di classe che hanno tutti gli oggetti.
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
Se tuttavia intendi il tipo con cui è stata dichiarata la variabile, non puoi ottenerlo. Ad esempio, se dici
val name: Object = "sam"
quindi riceverai comunque un String
rimborso dal codice sopra.
name.getClass.getSimpleName
per un output più leggibile
L'ho provato e ha funzionato
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5
è sia un'istanza diInt
che un'istanza diAny
. A parte questo, la tua spiegazione era perfetta :)