2012-10-24 9 views
7

我對Scala很陌生,並且對類型系統有疑問。Scala類型檢查器如何知道防止在已經平坦的List上調用flatten

flatten方法對嵌套集合起作用,所以如果我有一個List列表,它會將它壓平成List。但是在一個已經平坦的集合上打個扁叫是沒有意義的。當然,Scala類型檢查器會將其標記爲錯誤。

List(List(1,2,3),List(4,5,6)).flatten // produces List(1,2,3,4,5,6) 
List(1,2,3,4).flatten // type error 

據我所知,這在某種程度上依賴於一個隱式參數來扁平化。但是我不知道隱式值從何而來,以及它如何用來斷言被調用的對象的類型。另外,爲什麼不隱式參數顯示在List.flatten的scaladoc中?

回答

4

要理解它是如何工作的,我們需要看看扁平化的類型簽名:

def flatten[B](implicit asTraversable: (A) ⇒ GenTraversableOnce[B]): List[B] 

A是列表的元素類型和B是每個元素的元素的類型。爲了使拼合起作用,必須將元素類型隱式轉換爲GenTraversableOnce[B]。這只是集合的情況,或者如果你實現了自己的隱式轉換。例如,您可以爲成對定義一個:

implicit def pairToList[A](p:(A,A)) = List(p._1, p._2) 

List(1->2,2->3).flatten //compiles! List(1,2,2,3) 
+0

轉換不一定是隱式的,這也適用:List(1-> 2,3-> 4).flatten(p => List(p._1,p.2)) –

+1

當然,任何隱式參數也可以明確傳遞。 –

1

該技巧是一個隱式見證,確保列表中的元素可以遍歷。下面是flattenGenericTraversableTemplate採取的(略微簡化的)簽名:

def flatten[B](implicit asTraversable: A => TraversableOnce[B]) 
       : GenTraversable[B] = 

在你的情況,證人不能找到Int類型的元素,並且因此flatten調用是由編譯器拒絕。


如果你想使你的榜樣編譯,你可以使用下面的隱含定義:

implicit def singleToList[A](a: A) = List(a) 

(作爲一個側面說明:我會考慮這樣一個隱含的是相當危險的,因爲它是適用性非常普遍,這可能會導致不愉快的意外,因爲編譯器可能會在不知情的情況下在各個位置注入調用。)

+0

標準庫中是否存在隱式聲明要從List轉換爲TraversableOnce的地方?或者它只是自動存在,因爲List是TraversableOnce的子類型? –

相關問題