是什麼斯卡拉:瞭解參數多態性
def drop1[A](l: List[A]) = l.tail
和
def drop1(l: List[Int]) = l.tail
之間的差異提供的使用看起來像
?
什麼時候應該使用其中一個,爲什麼?儘管我能理解第二個例子,但我並不真正理解第一個例子的目的。
是什麼斯卡拉:瞭解參數多態性
def drop1[A](l: List[A]) = l.tail
和
def drop1(l: List[Int]) = l.tail
之間的差異提供的使用看起來像
?
什麼時候應該使用其中一個,爲什麼?儘管我能理解第二個例子,但我並不真正理解第一個例子的目的。
真的很簡單。你的第一個例子涉及泛型的概念。
泛型有一個簡單的目標,使某些方法泛型,例如非類型依賴。
讓我們看看這個微不足道的例子。假設我想爲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
總之 - 一些操作不依賴於特定類型,可以抽象化。計數蘋果和計數橙子本質上是相同的操作。如果你打算重複使用算法,那麼將一些類型抽象出來而不是寫出來會更方便
def countOranges(xs: List[Orange]) = { some code }
def countApples(xs: List[Apple]) = { the very same code }
感謝您的回答。我的第一個例子中爲什麼需要第一個'[A]'?它只是一個語法要求? – Caballero
是的,編譯器可以區分您從某個已定義的A類型引入的類型。爲什麼呢?防止你從錯誤中明確表達你的意圖。 –
謝謝。事實上,在閱讀本教程時,我提出了這個問題。 – Caballero