2010-09-20 176 views
23

我發現斯卡拉總是有任何「自然的解釋」。總是像「哦,但這只是一個函數被調用這個和那個對象與這個和那個參數」。從某種意義上說,沒有什麼是真正的編譯器魔法,因爲我們從其他語言中知道它。斯卡拉「< - 」爲理解

我的問題是關於< -運營商如下面的代碼中使用:

for(i <- 0 to 10) println(i) 

在這個例子中,我可以看到它被改寫成類似:

0.to(10).foreach((i:Int)=>println(i)) 

但這並不能解釋如何進入匿名yach函數在foreach函數中。在你寫的地方i它不是一個對象,也不是一個聲明的變量。那麼它是怎樣的呢?它是如何被傳播到內部的?

我的猜測是,我終於發現了一些東西,其實編譯器魔術

感謝您的時間。

爲了澄清,我的問題是:如何做的< - 在代碼的第一線操作人員的工作,因爲我不上它可作爲函數調用的對象。

回答

18

<-是一種語言 - 定義的關鍵字符號,與=>一樣,但與->(這是一個定義的符號)截然不同。因爲它是基本Scala語法的一部分,所以它可以用來創建綁定(在您的示例中爲i),這是用戶定義的結構無法完成的。

+0

這似乎是答案。如果可能的話,我會建議你記錄一下,現在有點兒出乎意料。 – Felix 2010-09-21 19:47:23

+4

@Felix:它在規範中有記錄。市面上幾乎所有的Scala書籍都涵蓋了它。 – missingfaktor 2010-09-21 20:19:38

+0

噢,我沒有得到一本書。等待權威2.8書 – Felix 2010-09-22 19:50:31

6

在這種情況下,它真的有點編譯器的魔力。從理解轉換到過濾器/地圖/平面地圖形式是一種特殊的解構方式,就像特殊形式的更新和應用方法的轉換一樣。

57

爲了增強Dave的答案,這裏是一個翻譯模式「換內涵」從Scala語言規範:

一個理解for (enums) yield e評估表達e由普查員枚舉每個綁定生成。枚舉器序列始終以發生器開始;這可以跟隨更多的生成器,值定義或警衛。

生成器p <- e從表達式e生成綁定,該表達式以某種方式與模式p匹配。值定義val p = e將值名稱p(或模式p中的多個名稱)綁定到評估表達式e的結果。警衛if e包含限制枚舉綁定的布爾表達式。

發電機和警衛的確切含義是通過翻譯定義調用的四種方法 :mapfilterflatMapforeach。這些方法可以針對不同的運營商類型以不同的方式實施。

翻譯方案如下。在第一步中,每個生成器p <- e,其中p不是無可辯駁的(§8。1)的e類型由

p <- e.filter { case p => true; case _ => false } 

然後更換,下面的規則重複施加直到所有推導已經 消除。

  • 一種用於-理解for (p <- e) yield e0被轉換爲e.map { case p => e0 }

  • A理解for (p <- e) e0被翻譯爲e.foreach { case p => e0 }

  • A理解for (p <- e; p0 <- e0 . . .) yield e00,其中。 。 。是一個(可能是空的)發生器或警衛序列,被翻譯爲 到:
    e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }

  • A理解for (p <- e; p0 <- e0 . . .) e00其中。 。 。是一個(可能是空的)發生器或警衛序列,被翻譯爲:
    e.foreach { case p => for (p0 <- e0 . . .) e00 }

  • 繼以保護if g發電機p <- e被轉換成一個單一的發生器:
    p <- e.filter((x1, . . . , xn) => g)
    其中x1。 。 。 ,xnp的自由變量 。

  • 後跟一個值定義val p0 = e0發電機p <- e被轉換 到對值,其中xx0是新鮮的名字的下面發生器:

    val (p, p0) <- 
        for([email protected] <- e) yield { val [email protected] = e0; (x, x0) } 
    
+1

好的,第一次閱讀後我不明白,但它很有趣:-)你從哪裏得到這個? – Felix 2010-09-21 19:50:08

+0

@Felix:正如我在答案的頂部所說的,它來自語言規範(可以從www.scala-lang.org下載) – missingfaktor 2010-09-21 20:21:13