2013-10-15 9 views

risposta

95

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.

+0

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

+0

@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. –

+1

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

14

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.

+1

È anche possibile fare 'name.getClass.getSimpleName' per un output più leggibile –

31

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

6

ho provato questo e ha funzionato

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