2016-08-04 46 views
1

此代碼預期返回true:如何TraversableLike.exists調用我的自定義集合的foreach

class MyList extends Traversable[Int] { 
    def foreach[U](f: Int => U) = { 
    f(1) 
    f(2) 
    f(3) 
    } 
} 
object Test extends App { 
    println(new MyList().exists(_ == 2)) 
} 

MyList只需要在爲了實現Traversable定義foreach。所以,exists函數調用MyList.foreach。設置斷點在f(1),我看到foreach被調用TraversableLike行352 for (x <- this)。那麼,是x <- this呼叫foreach?怎麼樣?我沒有看到任何地方撥打foreach

349: def exists(p: A => Boolean): Boolean = { 
    350: var result = false 
    351: breakable { 
    352:  for (x <- this) 
    353:  if (p(x)) { result = true; break } 
    354: } 
    355: result 
    366: } 
+0

我認爲這是''for'調用'foreach'。 –

+1

是的,編譯器將所有for'comprehensions重寫爲'map','flatMap'和'foreach'(無論哪個都需要)。 – jwvh

+2

請參閱http://stackoverflow.com/questions/9891407/getting-the-desugared-part-of-a-scala-for-comprehension-expression – mfirry

回答

1

關於For Comprehension and For Loops這個究竟會談斯卡拉規格:

發電機和警衛的確切含義是通過翻譯 定義的四種方法調用:mapwithFilterflatMapforeach。對於不同的 載體類型,這些方法可以以不同的方式實施。

所以翻譯實際上是:

def exists(p: A => Boolean): Boolean = { 
    var result = false 
    breakable { 
    this.foreach(x => if (p(x)) { result = true; break }) 
    } 
    result 
} 

這就是爲什麼你看到你的foreach被調用。

對於不同的理解,您可能會看到不同的翻譯,這些翻譯都在規範中指定。

1

Yuval是正確的。但總的來說,我發現提到他給的鏈接變得有點令人厭煩。特別是當我深入for循環內我不明白。

我開發了一個宏,幫助我弄清楚事情是如何去糖的。它非常方便,從scala REPL開始工作。只需打開一個會話,並在

import scala.language.experimental.macros 
import scala.reflect.macros.blackbox.Context 

// inspect how scala has desugared your code 
def traceSugar[T](t: T): T = macro impl 
def impl(c: Context)(t: c.Tree): c.Tree = { println(t); t } 

粘貼然後,如果你想看到的東西如何去糖,只是把它包在traceSugar。它將打印脫糖版本並評估表達式。非常方便的更有趣的for循環。在你的情況,

scala> traceSugar { 
| var result = false 
| breakable { 
|  for (x <- Seq(1,2,3)) 
|  if (x > 1) { result = true; break } 
| } 
| result 
| } 

結果

{ 
    var result: Boolean = false; 
    scala.util.control.Breaks.breakable(collection.this.Seq.apply[Int](1, 2, 3).foreach[Unit](((x: Int) => if (x.>(1)) 
    { 
     result = true; 
     scala.util.control.Breaks.break() 
    } 
    else 
    ()))); 
    result 
} 
res8: Boolean = true 

你看foreach,以及如何breakable作品。