Voglio ottenere il tipo di una variabile in fase di esecuzione. Come faccio a fare questo?Voglio ottenere il tipo di una variabile in fase di esecuzione
risposta
quindi, a rigor di termini, il "tipo di una variabile "è sempre presente e può essere passata 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 ciò che si vuole fare , che non vi aiuterà. Per esempio, può decidere di non sapere che cosa è il tipo di variabile, ma per sapere se il tipo del valoreè un certo tipo specifico, come ad esempio 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 cosa è il tipo della variabile, Any
. Ciò che conta, ciò che viene controllato è il tipo di 5
, il valore. In effetti, T
è inutile - si potrebbe anche averlo scritto def f(v: Any)
. Inoltre, utilizza ClassTag
o un valore Class
, che vengono spiegati di seguito e non è possibile controllare i parametri di tipo di un tipo: è possibile verificare se qualcosa è un List[_]
(List
di qualcosa), ma non è se, ad esempio, un List[Int]
o List[String]
.
Un'altra possibilità è che si desideri 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 lo ClassTag
o lo 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
vi permetterà anche di utilizzare i parametri del tipo che hai ricevuto sul match
.Questo non funziona:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
ma questo sarà:
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 utilizzando il contesto delimita sintassi, B : ClassTag
, che funziona proprio come il parametro implicito nel precedente esempio ClassTag
, ma utilizza una variabile anonima.
Si può anche ottenere un ClassTag
da un valore di Class
, in questo modo:
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 classe di base, ma non i suoi parametri di tipo. Cioè, lo per List[Int]
e List[String]
è lo stesso, List
. Se hai bisogno di parametri di tipo, allora devi usare un TypeTag
. Tuttavia, un TypeTag
non può essere ottenuto da un valore, né può essere utilizzato su una corrispondenza di modello, a causa della cancellazione di JVM.
Esempi con TypeTag
possono ottenere abbastanza complessa - nemmeno a confronto due tag di tipo non è esattamente semplice, come si può vedere qui 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
Naturalmente, ci sono modi per rendere il confronto tornare vero, ma richiederebbe alcuni capitoli di libri per coprire davvero lo TypeTag
, quindi mi fermerò qui.
Infine, forse non ti interessa affatto il tipo di variabile. Forse si vuole solo sapere che cosa è la classe di un valore, in questo caso la risposta è piuttosto semplice:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
Sarebbe meglio, però, per essere più precisi su ciò che si vuole realizzare, in modo che la risposta può essere più pertinente.
Se con il tipo di una variabile si intende la classe di runtime dell'oggetto a cui punta la variabile, è possibile ottenere ciò attraverso il riferimento di classe 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 tuttavia il tipo di dichiarazione della variabile, non è possibile ottenerlo. Ad esempio, se si dice
val name: Object = "sam"
allora si sarà ancora ottenere un String
indietro dal codice di cui sopra.
È anche possibile fare 'name.getClass.getSimpleName' per un output più leggibile –
Penso che la domanda sia incompleta. se si intende che si desidera ottenere le informazioni sul tipo di alcuni typeclass poi di seguito:
Se si desidera stampare come hai 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 si è in modalità repl poi
scala> :type List(1,2,3)
List[Int]
O se si vuole sapere che tipo della classe poi come @monkjack spiega "string".getClass
potrebbe risolvere lo scopo
ho provato questo e ha funzionato
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
- 1. Come ottenere il tipo generico in fase di esecuzione?
- 2. Impostazione tipo generico in fase di esecuzione
- 3. Utilizzo di una stringa come variabile in fase di esecuzione
- 4. Fortran - tipo di impostazione/precisione di una variabile in fase di esecuzione
- 5. Come ottenere il DiscriminatorValue in fase di esecuzione
- 6. scegliere una monade in fase di esecuzione
- 7. Ottenere l'output di un processo in fase di esecuzione
- 8. Specifica generico tipo di raccolta parametro in fase di esecuzione
- 9. Come ottenere il contenuto/tipo di file in fase di esecuzione
- 10. Tipo di variabile primitiva in fase di compilazione
- 11. In .NET, in fase di esecuzione: come ottenere il valore predefinito di un tipo da un oggetto Type?
- 12. Ottenere il tipo di una variabile nel codice C
- 13. Rimozione di una funzione in fase di esecuzione in PHP
- 14. Esecuzione di una fase Maven specifica
- 15. EF ottenere l'elenco di record in fase di esecuzione da Tipo
- 16. Determinare il tipo completo di una variabile
- 17. Android | Ottenere la versione OkHTTP Biblioteca in fase di esecuzione
- 18. Ottenere lo storyboard principale in fase di esecuzione
- 19. ottenere la versione artefatto Maven in fase di esecuzione
- 20. Unity: sostituisce il tipo registrato con un altro tipo in fase di esecuzione
- 21. C++ Determina il tipo di un oggetto polimorfico in fase di esecuzione
- 22. C'è un modo per ottenere il bytecode per una classe in fase di esecuzione?
- 23. Ottieni binding IIS in fase di esecuzione
- 24. Posso distinguere tra istanze di typeclass in fase di esecuzione?
- 25. Come posso tracciare una variabile in fase di esecuzione in C#?
- 26. Posso inserire una colonna in listview in fase di esecuzione?
- 27. Modifica implementazione/classe in fase di esecuzione
- 28. Modifica del valore di una macro in fase di esecuzione
- 29. Aggiungere animazione in fase di esecuzione
- 30. Chiamare una funzione generica con un parametro di tipo determinato in fase di esecuzione
Il codice di esempio che hai scritto dopo "Ma questo:" è fonte di confusione. Compila ma il risultato non è quello che mostri nei commenti. Entrambe le chiamate restituiscono lo stesso risultato: "A is a B". Poiché il valore '5' è sia un'istanza di' Int' che un'istanza di 'Any'. A parte questo, la tua spiegazione è stata perfetta :) – Readren
@Readren Il valore non è testato, la classe è. 'Int' è' Any', ma 'Any' non è' Int'. Funziona su Scala 2.10, e funziona _should_ su Scala 2.11, e non so perché non lo sia. –
Mi spaventa contraddire un'eminenza come te, ma il codice 'a match {case _: B => ...' verifica il tipo del valore attuale della variabile 'a', non il tipo della variabile' a '. Hai ragione nel restituire ciò che dici in scala 2.10.6. Ma dovrebbe essere un bug. In scala 2.11.8 il tipo del valore attuale viene testato, come dovrebbe. – Readren