2013-10-15 64 views

回答

95

所以,嚴格地說,「類型變量「總是存在的,並且可以作爲類型參數傳遞。例如:

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),但不是它是否是例如List[Int]List[String]

另一種可能是你想reify變量的類型。也就是說,你想將類型轉換爲一個值,所以你可以存儲它,傳遞它等。這涉及到反射,你將使用ClassTagTypeTag。例如:

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" 

一個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例子的隱含參數,但使用匿名變量。

你也可以從一個值的Class一個ClassTag,像這樣:

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 

一個ClassTag是有限的,因爲它僅覆蓋了基礎類,但不是它的類型參數。也就是說,ClassTag對於List[Int]List[String]是相同的,List。如果您需要類型參數,則必須改用TypeTag。但是,由於JVM的刪除,無法從值中獲得A TypeTag,也不能用於模式匹配。

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 

當然,也有辦法讓那個比較返回true,但它需要幾本書章節來真正涵蓋TypeTag,所以我會在這裏停下來。

最後,也許你根本不關心變量的類型。也許你只是想知道什麼是類的值,在這種情況下,答案很簡單:

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

這將是更好的,但是,更具體的瞭解你想要完成的任務,從而使答案可能更重要。

+0

你寫後的示例代碼「但是,這將:」令人困惑。它編譯,但結果不是你在評論中顯示的結果。這兩個調用返回相同的結果:「A是B」。因爲值'5'既是「Int」的實例又是「Any」的實例。 除此之外,你的解釋是完美:) – Readren

+0

@Readren值沒有測試,類是。 「Int」是「Any」,但「Any」不是「Int」。它適用於Scala 2.10,它應該適用於Scala 2.11,我不知道它爲什麼不是。 –

+1

它讓我害怕與你一樣的矛盾,但代碼'一個匹配{case _:B => ...'測試變量'a'的實際值的類型,而不是變量的類型'a '。 你是對的,它返回你在scala 2.10.6中說的話。但它應該是一個錯誤。 在scala 2.11.8中,應該測試實際值的類型。 – Readren

14

如果通過變量的類型您指的是變量指向的對象的運行時類,那麼您可以通過所有對象具有的類引用來獲得此類。

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

如果你的意思是變量被聲明爲的類型,那麼你不能得到那個。例如,如果你說

val name: Object = "sam" 

那麼你仍然會得到一個String從上面的代碼後面。

+1

你也可以做'name.getClass.getSimpleName'一個更可讀的輸出 –

31

我認爲這個問題並不完整。如果你的意思是,你希望得到一些類型類,然後下面的類型的信息:

如果你想打印爲您指定然後:

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] 

如果你在REPL模式,那麼

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

或者,如果你只是想知道那麼該類鍵入的內容向@monkjack解釋"string".getClass可能會解決這個目的

6

我已經測試和它的工作

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