2015-04-21 91 views
0

我最近碰到這個例子跑,它打印「[7]」使用參數化類型參數聲明一個方法的優點與聲明參數爲Any?

class Decorator(left: String, right: String) { 
    def layout[A](x: A) = left + x.toString() + right 
} 

def apply(f: Int => String, v: Int) = f(v) 
val decorator = new Decorator("[", "]") 
println(apply(decorator.layout, 7)) 

這也有可能宣佈Decorator這樣的:

class Decorator(left: String, right: String) { 
    def layout(x: Any) = left + x.toString() + right 
} 

我很好奇,想知道是什麼第一種方法的優點?

回答

2

在給出的具體示例中,沒有太大區別,因爲您對該值做的唯一操作是調用方法toString,該方法在Any上定義,因此可用於Scala中的任何值。

但是,通常情況下,您可能希望保存該數據並在以後使用。比方說,我們有一個名爲Cat一個自定義類型:

case class Cat(name: String) { 
    def speak() = print(s"Meow, my name is $name.\n") 
} 

我們可能想要存儲的貓名單,仍然能夠得到貓淘汰名單的後面,並把它們作爲貓。 List[A]班允許我們這樣做。請注意,它有一個類型參數A,它將允許它記住它所保存的事物的類型,並稍後以正確的類型返回它們。例如,我們可以編寫一個函數來讓我們列表中的所有貓都說話。

def processCats(cats: List[Cat]) = 
    cats.foreach((cat:Cat) => cat.speak) 

這是可能的,因爲foreach內部變量cat的類型爲Cat,所以我們可以稱之爲Cat的方法。

如果List不是通用的,那麼變量cat將不能具有類型Cat,如果沒有運行時轉換,我們將無法使用它。 List實際上並沒有這樣的工作,但我們可以模擬它:

type NonGenericList = List[Any] 

def nonGenericProcessCats(cats: NonGenericList) = 
    cats.foreach((catAsAny:Any) => { 
     val cat = catAsAny.asInstanceOf[Cat] 
     cat.speak 
    }) 

這一次,在foreach變量catAsAny具有類型Any。我們可以使用asInstanceOf將它轉換爲Cat,但現在我們要記住這個類型,如果我們記錯了,演員陣容在運行時會失敗,導致我們的程序崩潰。通過泛型,編譯器可以跟蹤我們的正確類型。