3 回答

TA貢獻(xiàn)1812條經(jīng)驗(yàn) 獲得超5個(gè)贊
這個(gè):
x foreach println(_ + 1)
等效于此:
x.foreach(println(x$1 => x$1 + 1))
沒有跡象表明的類型可能是什么x$1,并且說實(shí)話,打印函數(shù)沒有任何意義。
您(對(duì)我而言)顯然打算打印x$0 + 1,而x$0參數(shù)傳遞到的位置foreach。但是,讓我們考慮一下...... foreach以a作為參數(shù)Function1[T, Unit],其中T是列表的類型參數(shù)。foreach相反println(_ + 1),您傳遞給的是返回的表達(dá)式Unit。
如果您寫了,相反x foreach println,您將傳遞完全不同的東西。您將傳遞function(*)println,該函數(shù)接受Any并返回Unit,因此符合的要求foreach。
由于的擴(kuò)展規(guī)則,這有點(diǎn)令人困惑_。它擴(kuò)展到最里面的表達(dá)式定界符(括號(hào)或花括號(hào)),除非它們代替了參數(shù),在這種情況下,它意味著另一件事:部分函數(shù)應(yīng)用程序。
為了更好地解釋這一點(diǎn),請(qǐng)看以下示例:
def f(a: Int, b: Int, c: Int) = a + b + c
val g: Int => Int = f(_, 2, 3) // Partial function application
g(1)
在這里,我們將第二個(gè)和第三個(gè)參數(shù)應(yīng)用于f,并返回一個(gè)僅需要剩余參數(shù)的函數(shù)。請(qǐng)注意,它只能按原樣工作,因?yàn)槲抑赋隽说念愋蚲,否則我必須指出未應(yīng)用的參數(shù)的類型。讓我們繼續(xù):
val h: Int => Int = _ + 1 // Anonymous function, expands to (x$1: Int => x$1 + 1)
val i: Int => Int = (_ + 1) // Same thing, because the parenthesis are dropped here
val j: Int => Int = 1 + (_ + 1) // doesn't work, because it expands to 1 + (x$1 => x$1 + 1), so it misses the type of `x$1`
val k: Int => Int = 1 + ((_: Int) + 1) // doesn't work, because it expands to 1 + (x$1: Int => x$1 + 1), so you are adding a function to an `Int`, but this operation doesn't exist
讓我們k更詳細(xì)地討論,因?yàn)檫@是非常重要的一點(diǎn)?;叵胍幌逻@g是一個(gè)函數(shù)Int => Int,對(duì)嗎?所以,如果我要輸入1 + g,這有意義嗎?這就是在中所做的k。
使人們感到困惑的是他們真正想要的是:
val j: Int => Int = x$1 => 1 + (x$1 + 1)
換句話說,他們希望x$1替換對(duì)象_跳到括號(hào)之外,并跳到正確的位置。這里的問題是,盡管對(duì)他們來說合適的地方似乎很明顯,但對(duì)于編譯器來說卻并不明顯??紤]以下示例,例如:
def findKeywords(keywords: List[String], sentence: List[String]) = sentence.filter(keywords contains _.map(_.toLowerCase))
現(xiàn)在,如果將其擴(kuò)展到括號(hào)之外,我們將得到:
def findKeywords(keywords: List[String], sentence: List[String]) = (x$1, x$2) => sentence.filter(keywords contains x$1.map(x$2.toLowerCase))
這絕對(duì)不是我們想要的。事實(shí)上,如果_沒有得到由最里面的表達(dá)式分隔符為界,一個(gè)永遠(yuǎn)無法使用_嵌套map,flatMap,filter和foreach。
現(xiàn)在,回到匿名函數(shù)和部分應(yīng)用程序之間的混淆,請(qǐng)看這里:
List(1,2,3,4) foreach println(_) // doesn't work
List(1,2,3,4) foreach (println(_)) // works
List(1,2,3,4) foreach (println(_ + 1)) // doesn't work
由于操作符號(hào)的工作方式,第一行不起作用。Scala只是看到printlnreturn Unit,這不是foreach期望的。
第二行之所以起作用,是因?yàn)槔ㄌ?hào)使Scala println(_)可以整體評(píng)估。這是一個(gè)部分函數(shù)應(yīng)用程序,因此它返回Any => Unit,這是可以接受的。
第三行不起作用,因?yàn)樗黖 + 1是匿名函數(shù),您將其作為參數(shù)傳遞給println。您并沒有成為println匿名函數(shù)的一部分,而這正是您想要的。
最后,很少有人期望:
List(1,2,3,4) foreach (Console println _ + 1)
這可行。為什么這樣做留給讀者練習(xí)。:-)
(*)實(shí)際上println是一種方法。在編寫時(shí)x foreach println,您沒有在傳遞方法,因?yàn)闊o法傳遞方法。相反,Scala創(chuàng)建一個(gè)閉包并將其傳遞。它像這樣擴(kuò)展:
x.foreach(new Function1[Any,Unit] { def apply(x$1: Any): Unit = Console.println(x$1) })

TA貢獻(xiàn)1995條經(jīng)驗(yàn) 獲得超2個(gè)贊
下劃線有點(diǎn)棘手。根據(jù)規(guī)范,該短語:
_ + 1
相當(dāng)于
x => x + 1
試
x foreach println (y => y + 1)
產(chǎn)量:
<console>:6: error: missing parameter type
x foreach println (y => y + 1)
如果您在其中添加一些類型:
x foreach( println((y:Int) => y + 1))
<console>:6: error: type mismatch;
found : Unit
required: (Int) => Unit
x foreach( println((y:Int) => y + 1))
問題是您要傳遞一個(gè)匿名函數(shù)給println它,而它不能處理它。您真正想要做的是(如果您嘗試將繼承者打印到列表中的每個(gè)項(xiàng)目上):
x map (_+1) foreach println

TA貢獻(xiàn)1846條經(jīng)驗(yàn) 獲得超7個(gè)贊
Welcome to Scala version 2.8.0.Beta1-prerelease (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val l1 = List(1, 2, 3)
l1: List[Int] = List(1, 2, 3)
scala>
scala> l1.foreach(println(_))
1
2
3
添加回答
舉報(bào)