2013-07-15 24 views
2

我已經閱讀了一些其他問題,例如What are all the uses of an underscore in Scala?,雖然我確定這個問題已經被問到,但我不能通過所有其他17000個Scala問題。佔位符語法不能保留我的地方

Foreach have strange behaviourPlaceholder not useful,但它似乎仍然是一個hidden feature

scala> val is = (1 to 5) toList 
is: List[Int] = List(1, 2, 3, 4, 5) 

scala> is foreach { i => println("Hi.") ; Console println 2 * i } 
Hi. 
2 
Hi. 
4 
Hi. 
6 
Hi. 
8 
Hi. 
10 

scala> is foreach { println("Hi.") ; Console println 2 * _ } 
Hi. 
2 
4 
6 
8 
10 

有人可以解釋我請的區別?

如果你感到了一陣熱潮,並嘗試:

scala> is foreach { i => println("Hi!") ; Console println 2 * i } 
java.lang.IllegalArgumentException: !") ; Console println 2 * i }: event not found 

然後看看this answer.是的,真正發生了。

+0

編者按:這個問題問得@ sschaef干預之前有趣很多。批評者有義務在存在的情況下找到該複製品;幾頁谷歌結果說不。 –

+0

我看不出有什麼好笑的,當我毀掉你的笑話時,我很抱歉。對我來說,這看起來像醉漢的意圖。還有一些孿生兄弟,至少我懶得去搜索他們。 – sschaef

+0

@sschaef對我很有趣,就是。在Scala中有N種方式來做所有事情(他們說)導致指數問題。但謝謝你的清理。 –

回答

3

Landei有正確的答案,我想,但它不是解壓得很徹底。讓我們開始在最後:

scala> Console println 2 * _ 
<console>:8: error: missing parameter type for expanded function 
((x$1) => Console.println(2.$times(x$1))) 
       Console println 2 * _ 
           ^

好了,所以我們看到自身,Console println 2 * _正試圖通過建立明確的ETA擴張的功能,但它不知道返回參數類型,因此它不能。

現在讓我們試試一個返回函數的代碼塊。

scala> { println("Hi"); (i: Int) => i*5 } 
Hi 
res1: Int => Int = <function1> 

所以,一切,你執行整個塊(包括像println副作用的語句),並返回返回值是你的函數。

現在,正如Landei所說,佔位符語法只適用於一個(簡單)表達式中的一個參數,而在第二種情況下,我們沒有簡單的表達式,而是具有塊表達式(由兩個簡單表達式組成)。所以我們使用佔位符語法而不是,我們正在創建一個函數。我們做一個代碼塊:

is foreach { println("Hi.") ; Console println 2 * _ } 

它,因爲我們沒有與函數參數開始,被解釋爲一個普通的參數,但我們可以在幾乎任何環境 - 參數列表包括 - 更換一個簡單的表達式(x)與塊表達式{ stuff; x }。因此,我們可以把它看作

is foreach ({ println("Hi.") ; Console.println 2 * _ }) 

現在類型inferencer知道什麼返回類型應該是,所以它運行的代碼塊打印出「你好」,並創建了一個函數,然後通過該功能(只是一次,在開始!)到foreach。如果inferencer可以看看跨行類型弄清楚類型,這將是相同的:

val temp = { println("Hi."); Console.println 2 * _ } 
is foreach (temp) 
+0

「因爲我們沒有一個表達」是誤導。我們有塊表達式,並且一個arg列表可以是(exprs)或{block},沒有必要在parens中包含的含義(隱式地,概念上)。塊expr包含{block}和{cases}。 –

+0

@ som-snytt - 我用更多技術上正確的術語改進了我的描述。 –

7

佔位符語法適用於一個表現,而不是針對整個塊,所以你的例子解釋爲{ println("Hi."); i => Console println 2 * i }

+0

順便說一下,這是第一個Scala Puzzler ;-) http://scalapuzzlers.com/#pzzlr-001 –

相關問題