在Scala lambda函数中使用_
在Scala中,当你写a.groupBy(_)
时,编译器将其解析为一个匿名函数:x => a.groupBy(x)
。根据Scala规范§6.23,表达式中的下划线占位符将被替换为一个匿名参数。因此:
_ + 1
扩展为x => x + 1
f(_)
扩展为x => f(x)
_
本身不会被扩展(占位符不是任何表达式的一部分)。
表达式x => a.groupBy(x)
会让编译器困惑,因为它无法推断出x
的类型。如果a
是一个类型为E
的集合元素,则编译器期望x
是一个类型为(E) => K
的函数,但无法推断出类型K
...
谢谢。但是,为什么a.mapValues(_.size)
不被解析为x => a.mapValues(x.size)
?
因为_.size
是一个表达式。比较:List(1,2,3).map( 2 + twice(_) )
和List(1,2,3).map( twice(1+_) )
,其中twice
是一个将输入加倍的函数。
: 但是_
也是一个表达式;它是一个表示在其上调用方法的值的表达式。而整个a.mapValues(_.size)
也是一个表达式。包含这行代码的任何代码块也是一个表达式。我认为我对它的工作方式有一个直观的基本正确的理解,但是是否有一个明确的定义来解释Scala编译器会“走多远”的范围?也就是说,为什么它不仅仅将_
转换为x => x
,而是将_.size
转换为x => s.size
?
我认为它在第一个方法应用之后停止。请记住,在Scala中,_.size
,_ + 1
,fn(_)
等都被转换为方法应用。
: _
将最内层“正确包含”它的Expr
转换为一个函数。这里的“正确包含”意味着“包含_
并且还包含至少一个其他单词或符号”。这将排除_
本身成为身份函数的可能性。Expr
是一种特定类型的表达式,这是一种语法上的区别。特别是函数调用的每个参数以及括号中的几乎任何其他表达式都是Expr
。
Scala中lambda函数中使用下划线(_)的原因和解决方法
在Scala中,lambda函数是一种匿名函数,可以通过使用下划线(_)来部分应用方法或函数。下划线的使用方式有三种,分别是用于部分应用方法的参数、用于匿名函数的位置参数和用于将方法转换为方法值。
在第一个例子中,使用下划线对表达式进行部分应用,它代表的是位置参数。例如,a.groupBy(_)
中的下划线代表着将groupBy方法应用到参数a上,但是第二个参数未应用。
在第二个例子中,使用下划线对mkString方法进行部分应用,同样代表位置参数。例如,a.mkString("<", _, ">")
中的下划线代表将"<"这个参数应用到mkString方法的第一个位置参数上,但第二个参数和第三个参数未应用。
当使用下划线作为表达式时,它代表位置参数,这很容易引起混淆。例如,a.mapValues(_.size)
和a.mapValues(x => x.size)
都会生成匿名函数,但是它们实际上是不同的。
此外,还有一个特殊情况,下划线用于将方法转换为方法值,也是一种匿名函数。例如,a.groupBy _
将groupBy方法转换为方法值。
因此,在Scala中,下划线的使用方式可能会引起混淆,特别是在匿名函数中使用。为了避免混淆,可以明确指定参数,或者使用完整的匿名函数定义来替代使用下划线的部分应用方法。