2012-09-06 110 views
1

在下面的代碼中,放置query對象(在循環內部還是外部)的位置是否重要?爲了便於閱讀,我更喜歡這個第一版:斯卡拉優化這個代碼嗎?

class MyClass { 
    db withSession { 
    names.foreach { name => 
     val query = MyEntity.createFinderBy(_.name) <---------- 
     query.list(text).foreach(res => 
     doSomething 
     } 
    } 
    } 
} 

但是這不是第二版更好嗎?

class MyClass { 
    db withSession { 
    val query = MyEntity.createFinderBy(_.name) <---------- 
    names.foreach { name => 
     query.list(text).foreach(res => 
     doSomething 
     } 
    } 
    } 
} 

甚至?

class MyClass { 
    val query = MyEntity.createFinderBy(_.name) <---------- 
    db withSession { 
    names.foreach { name => 
     query.list(text).foreach(res => 
     doSomething 
     } 
    } 
    } 
} 

在Java中,我把它放在一個靜態的最終場在班上名列前茅......

+7

爲什麼你會發現第一個更具可讀性?最後的版本更直接地表達了查詢不依賴於會話或循環中發生的任何事情的信息。即使其他人被優化了,我也會親自選擇它(它們可能不是)。 –

+1

我更喜歡1st,因爲查詢在使用時更接近。但我明白你的觀點,並喜歡它。 – Renaud

回答

2

不,它不需要,因爲在第一個例子中,你明確告訴它來調用createFinderBy(也是list)。不能保證這些方法每次都會返回相同的值(即引用透明),所以這些值不能被記憶,或者代碼被優化爲第二或第三個例子。

這將是一個很好的功能,如果你可以註釋方法,或者如果編譯器可以解決它,但目前它不。

順便說一句,你可以讓它存儲在mutable.Map緩存值,並使用getOrElseUpdate方法,如果您的查詢已經在地圖,否則計算查詢返回一個緩存值返回值改變createFinderBy方法並緩存它。

2

scalac沒有(不能)優化你的代碼,因爲它不使用效果系統。這使得scalac幾乎不可能關心優化是否會破壞代碼。例如,如果MyEntity.createFinderBy(_.name)不是純粹的(也許它會增加一個計數訪問次數的計數器),它將在一次或每次迭代中執行一次更改。

在這種情況下我可以建議改變功能字面的位置:

scala> 1 to 3 foreach {x => println("x"); println(x)} 
x 
1 
x 
2 
x 
3 

scala> 1 to 3 foreach {println("x"); x => println(x)} 
x 
1 
2 
3 

在返回傳遞給FOREACH的功能的塊被創建的第二個例子(後執行的其他表達式),而在前一個,整塊是一個單一的功能。