匿名类函数的占位符语法
考虑下面的代码:
val numSeq=Array(3.1415,2.71828,9.8)
下面想用foreach
方法输出它们的整数,如果用占位符语法,比如下面这样:
scala> numSeq foreach (println(_.toInt))
<console>:13: error: missing parameter type for
expanded function ((x$1: <error>) => x$1.toInt)
numSeq.foreach(println(_.toInt))
^
看起来,我们本意是将println(_.toInt)
解释为x=>println(x.toInt)
,但是编译器却理解为x=>x.toInt
,自然不对。这是因为,添加了一对括号后((_.toInt)
)就形成了新的词法作用域,因此println(_.toInt)
会被解读为println(x=>x.toInt)
。
(参考:Scala placeholder syntax for anonymous function)
既然如此,不妨去掉括号看看:
scala> numSeq foreach (println_.toInt) 没有加空格
<console>:13: error: not found: value println_
numSeq foreach (println_.toInt)
^
很容易错的地方,就是在函数名和下划线之间不加空格,这就会将println_
看做一个标识符。
scala> numSeq foreach (println _.toInt)
<console>:1: error: ')' expected but '.' found.
numSeq foreach (println _.toInt)
注意,scala里面,使用method()
可以简写为method
,但是method(x)
不能省略括号method x (错误)
。(这是Groovy的语法,搞混了_(:зゝ∠)_)
有一个特殊的下划线用法,也就是说,指代整个参数列表,就可以写成method _
,所以,println _.toInt
事实上是println _
,显然后跟.toInt
就不合理了,因为这就变成( x=>println(x) ).toInx
,语法错误。
那么该怎么做呢?注意到在scala里,如果对象obj
调用一个方法method
,而该方法只接受一个参数x
,那么obj.method(x)
可以简写为obj method x
或 obj method (x)
,看起来method
就不是一个方法名而是一个中缀操作符,换言之
scala> numSeq foreach (Console println _.toInt)
3
2
9
此时,编译器明确是三部分,所以_.toInt
就被视为一个整体,从而Console println _.toInt
就被翻译成我们需要的x=>Console.println(x,toInt)
现在想要将numSeq
升序排序:
scala> numSeq.sortWith{ _.compareTo(_)<0 }
res93: Array[Double] = Array(2.71828, 3.1415, 9.8)
_.compareTo(_)<0
实际上是(x,y) => { x.compareTo(y)<0 }
更多参考:scala 下划线解析报错: missing parameter type for expanded func
下划线文法的就近展开原则原则:
Underscores extend outwards to the closest closing Expr : top-level expressions or expressions in parentheses
匿名函数简写注意事项:
所以当匿名函数有多个括号嵌套的时候,不要使用_的简写方式 ,而应该用普通匿名函数的书写方式。比如 (x:Int,y:Int)=> (x*2)+f(y+2)
_本身构不成一个表达式:expressions,所以如下是允许的
scala> List(1,2,3,4).foreach(print(_))
=>List(1,2,3,4).foreach(print _)
=>List(1,2,3,4).foreach(print)
=>List(1,2,3,4) foreach print
=>List(1,2,3,4) foreach print _
网友评论