2015-11-06 24 views
0
sealed trait List[+A] // `List` data type, parameterized on a type, `A` 
case object Nil extends List[Nothing] // A `List` data constructor representing the empty list 
/* Another data constructor, representing nonempty lists. Note that `tail` is another `List[A]`, 
which may be `Nil` or another `Cons`. 
*/ 
case class Cons[+A](head: A, tail: List[A]) extends List[A] 

我的問題是A前面的「+」是什麼? 爲什麼在這裏「列表[A]」加號被忽略?帶前面加號的scala類型

由於

+2

http://stackoverflow.com/questions/663254/why-doesnt-the-example-compile-aka-how-does-co-contra-and-in-variance-w – Rumoku

+2

我讀過寫得很好的帖子,由'先生聯繫起來。 V.',瞭解它之前幾次。所以不要氣餒。 –

回答

4

在一種類型的構造器參數的前面的一個加號或減號意味着該類型的值出現在協變(+)或逆變(-)位置。協變位置意味着該類型僅出現爲「輸出」或返回類型,與List的情況一樣。然後,List[A]List[B]如果A <: B的一個亞型,如果AB子類型:

trait Animal { def food: String } 
case class Dog(name: String) extends Animal { def food = "all" } 

def test(xs: List[Animal]) = xs.map(_.food) 

test(List(Dog("Jussi"))) 

在這裏,您可以傳遞一個List[Dog]List[Animal]因爲List[Dog] <: List[Animal]

逆變是相反的 - 該類型僅作爲輸入發生。例如Function1[A, Out] <: Function1[B, Out]如果A >: B,如果AB的超級類型。

def test(fun: Dog => String): String = fun(Dog("Jussi")) 

test { x: Animal => x.food } 

在這裏,您可以傳遞一個Animal => StringDog => String,因爲前者是子類型後者。


方差註釋+-永遠只發生在類型的定義,所以在List[+A]的定義,而不是任何其他地方使用,其中List,例如作爲類型歸屬或在extends子句中,因爲方差一旦定義就不能改變。這被稱爲定義站點差異。


由於Nothing底部類型Scala中,一個類型是子類的任何其它類型的,就可以因此具有方便object Nil extends List[Nothing],從而Nil成爲子類型的List[A]任何可能的A。無論何時需要列表,無論元素類型如何,都可以使用Nil