实际上,您必须后退一步。
您误解了牙套的工作原理。
scala> val is = (1 to 5).toList
is: List[Int] = List(1, 2, 3, 4, 5)
scala> is map ({ println("hi") ; 2 * _ })
hi
res2: List[Int] = List(2, 4, 6, 8, 10)
如果println
是传递给 的函数的一部分map
,您会看到更多问候。
scala> is map (i => { println("hi") ; 2 * i })
hi
hi
hi
hi
hi
res3: List[Int] = List(2, 4, 6, 8, 10)
您的额外大括号是一个块,它是一些语句,后跟一个结果表达式。结果 expr 是函数。
一旦你意识到只有结果 expr 的预期类型是 预期的函数map
,你就不会考虑在前面的语句中使用下划线,因为裸下划线需要预期的类型来确定下划线的含义。
那是类型系统告诉您下划线不在正确的位置。
附录:在您提出的评论中:
如何使用下划线语法将函数文字的参数绑定到变量
这是一个“愚蠢”的问题,请原谅这种表达方式吗?
下划线是这样你不必命名参数,然后你说你想命名它。
一个用例可能是:传入的参数很少,但我只想命名其中一个。
scala> (0 /: is)(_ + _) res10: Int = 15
scala> (0 /: is) { case (acc, i) => acc + 2 * i } res11: Int = 30
这不起作用,但有人可能想知道为什么。也就是说,我们知道折叠期望什么,我们想应用带有 arg 的东西。哪个参数?在部分应用的偏函数之后剩下的任何东西。
scala> (0 /: is) (({ case (_, i) => _ + 2 * i })(_))
或者
scala> (0 /: is) (({ case (_, i) => val d = 2 * i; _ + 2 * d })(_))
SLS 6.23“匿名函数的占位符语法”提到了“expr”边界,当你必须知道下划线代表什么时——它本身不是一个范围。如果您为下划线提供类型归属,它仍然会抱怨预期的类型,大概是因为类型推断是从左到右的。