3 回答

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

TA貢獻1995條經驗 獲得超2個贊
下劃線有點棘手。根據規范,該短語:
_ + 1
相當于
x => x + 1
試
x foreach println (y => y + 1)
產量:
<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))
問題是您要傳遞一個匿名函數給println它,而它不能處理它。您真正想要做的是(如果您嘗試將繼承者打印到列表中的每個項目上):
x map (_+1) foreach println

TA貢獻1846條經驗 獲得超7個贊
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
添加回答
舉報