Відповіді:
Отже, строго кажучи, "тип змінної" присутній завжди і може передаватися як параметр типу. Наприклад:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
Але залежно від того, що ви хочете зробити , це вам не допоможе. Наприклад, може знадобитися не знати, що це за тип змінної, а знати, чи є тип значення якимсь конкретним типом, наприклад таким:
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
Тут не має значення , що тип змінної Any. Важливим є те, що перевіряється тип 5, значення. Насправді Tце марно - ти міг би, def f(v: Any)натомість, написати це . Крім того, тут використовується ClassTagабо значення Class, або значення , які описані нижче, і не може перевірити параметри типу типу: ви можете перевірити, чи є щось List[_]( Listчимось), але не є, наприклад, a List[Int]чи List[String].
Інша можливість полягає в тому, що ви хочете переоцінити тип змінної. Тобто, ви хочете перетворити тип на значення, щоб ви могли зберігати його, передавати і т. Д. Це передбачає відображення, і ви будете використовувати або ClassTagабо a TypeTag. Наприклад:
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дозволяє вам використовувати параметри типу, які ви отримали match. Це не спрацює:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
Але це:
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)
Тут я використовую синтаксис контекстуB : ClassTag , який працює так само, як неявний параметр у попередньому ClassTagприкладі, але використовує анонімну змінну.
Також можна отримати ClassTagзначення зі значення Class, наприклад:
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обмежений тим, що охоплює лише базовий клас, але не параметри його типу. Тобто, ClassTagfor List[Int]і List[String]однаковий List,. Якщо вам потрібні параметри типу, тоді ви повинні використовувати TypeTagзамість. TypeTagОднак, не може бути отримана з значення, і не може бути використаний на зіставлення з зразком, в зв'язку з JVM в стиранням .
Приклади з TypeTagможуть стати досить складними - навіть порівняння двох тегів типу не є зовсім простим, як це видно нижче:
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
Звичайно, існують способи зробити це порівняння справжнім, але для цього потрібно було б кілька розділів книг, щоб насправді охопити TypeTag, тому я зупинюсь на цьому.
Нарешті, можливо, вас взагалі не хвилює тип змінної. Можливо, ви просто хочете знати, що таке клас значення, і в цьому випадку відповідь досить проста:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
Однак було б краще визначитися конкретніше з тим, що ви хочете досягти, щоб відповідь була більш конкретною.
Intє Any, але Anyні Int. Він працює на Scala 2.10, і він повинен працювати на Scala 2.11, і я не знаю, чому це не так.
a match { case _: B => ...перевіряє тип фактичного значення змінної a, а не тип змінної a. Ви маєте рацію, повертаючи те, що ви говорите в масштабі 2.10.6. Але це повинна бути помилка. У шкалі 2.11.8 тип фактичного значення перевіряється, як і слід.
Я думаю, що питання неповне. якщо ви мали на увазі, що хочете отримати інформацію про тип якогось класу типів, то нижче:
Якщо ви хочете надрукувати, як ви вказали тоді:
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]
Якщо ви перебуваєте в режимі відтворення, тоді
scala> :type List(1,2,3)
List[Int]
Або якщо ви просто хочете знати, який тип класу, то, як пояснює @monkjack, "string".getClassможе вирішити ціль
typeof x, тут manOf(x)говорять про тип даних!
Якщо під типом змінної ви маєте на увазі клас середовища виконання об'єкта, на який вказує змінна, то ви можете отримати це за допомогою посилання на клас, яке є у всіх об'єктів.
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
Якщо ви, однак, маєте на увазі тип, яким була оголошена змінна, тоді ви не можете цього отримати. Наприклад, якщо ви скажете
val name: Object = "sam"
тоді ви все одно отримаєте Stringвідступ від наведеного вище коду.
name.getClass.getSimpleNameдля більш читабельного результату
я це перевірив, і це спрацювало
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5є і екземпляром,Intі екземпляромAny. Окрім цього, ваше пояснення було чудовим :)