2014-01-14 94 views
3

是什麼斯卡拉:瞭解參數多態性

def drop1[A](l: List[A]) = l.tail 

def drop1(l: List[Int]) = l.tail 

之間的差異提供的使用看起來像

​​

什麼時候應該使用其中一個,爲什麼?儘管我能理解第二個例子,但我並不真正理解第一個例子的目的。

回答

6

真的很簡單。你的第一個例子涉及泛型的概念。

泛型有一個簡單的目標,使某些方法泛型,例如非類型依賴。

讓我們看看這個微不足道的例子。假設我想爲List寫一個drop1方法。

我可以寫一個爲每一個類型:(慢,重複):

def drop1(l: List[Int]): List[Int] = l.tail // this only works for Int 

def drop1(l: List[String]): List[String] = l.tail // this only works for String 

你可以看到你怎麼也得寫上爲每一個類型。爲了克服這一點,你有仿製藥:

def drop1[A](l: List[A]): List[A] = l.tail // this works for any given type. 

這基本上說:不管列表中包含的類型是什麼,給我尾巴。 而不是寫幾千個變種的drop1幾乎無限的類型,我只需要寫一個。

現在在Scala中,你的實現是最好的實現:

implicit class ListOps[A](val l: List[A]) extends AnyVal { 
    def drop1: List[A] = l match { 
    case head :: tail => tail 
    case Nil => Nil 
    } 
} 
// you can now have 
List(1, 2, 3).drop1 

這也是一般一個壞主意,重命名衆所周知庫方法。 A tail操作不安全,drop是安全的。由於存在默認的drop方法,因此您所造成的一切都很混亂。

List(1, 2, 3) drop 1 
+0

感謝您的回答。我的第一個例子中爲什麼需要第一個'[A]'?它只是一個語法要求? – Caballero

+2

是的,編譯器可以區分您從某個已定義的A類型引入的類型。爲什麼呢?防止你從錯誤中明確表達你的意圖。 –

+0

謝謝。事實上,在閱讀本教程時,我提出了這個問題。 – Caballero

3

總之 - 一些操作不依賴於特定類型,可以抽象化。計數蘋果和計數橙子本質上是相同的操作。如果你打算重複使用算法,那麼將一些類型抽象出來而不是寫出來會更方便

def countOranges(xs: List[Orange]) = { some code } 
def countApples(xs: List[Apple]) = { the very same code }