【问题标题】:Usage of _ in scala lambda functions在 Scala lambda 函数中使用 _
【发布时间】:2011-10-06 11:22:14
【问题描述】:

谁能解释一下为什么我可以这样做:

a.mapValues(_.size)

而不是

a.mapValues(x => x.size)

但我做不到

a.groupBy(_)

而不是一个

a.groupBy(x => x)

【问题讨论】:

  • 在需要功能的情况下可以使用identityx => x:a groupBy identity
  • @incrop 感谢您的提示,我从未注意到身份功能已经在Predef...

标签: scala


【解决方案1】:

当您编写 a.groupBy(_) 时,编译器会将其理解为匿名函数:

x => a.groupBy(x)

根据 Scala 规范 §6.23,表达式中的下划线占位符被匿名参数替换。所以:

  • _ + 1 扩展为 x => x + 1
  • f(_) 扩展为 x => f(x)
  • _ 本身不会扩展(占位符不是任何表达式的一部分)。

表达式x => a.groupBy(x) 会混淆编译器,因为它无法推断x 的类型。如果aE 类型元素的某个集合,那么编译器期望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 是一个将输入加倍的函数。
  • @paradigmatic: 但_ 也是一个表达式;它是一个表达式,表示调用方法的值。整个a.mapValues(_.size) 也是一个表达式。与包含此行的任何块一样。我想我对它的工作原理有一个直观的、大部分正确的处理方式,但是对于 Scala 编译器究竟“走多远”有一个很好的定义吗?即为什么它不会停止将_变成x => x,但确实停止将_.size变成x => s.size
  • 我认为它在第一种方法应用后停止。请记住,_.size_ + 1fn(_) 等都被转换为 Scala 中的方法应用程序。
  • @Ben: _ 从最里面的Expr 中创建一个正确包含它的函数。措辞“正确包含”是指“包含_以及其他内容,至少一个其他单词或符号”。这将 _ 排除在身份功能之外。 Expr 是一种特殊的表达式。这是语法上的区别。特别是函数调用的每个参数,以及括号中的几乎所有其他表达式,都是Expr
【解决方案2】:

这里不容易看到:

a.groupBy(_)

但在这样的情况下更容易看到它:

a.mkString("<", _, ">")

我正在部分应用方法/功能。我将它应用于一些参数(第一个和最后一个),而第二个参数未应用,所以我得到了一个像这样的新函数:

x => a.mkString("<", x, ">")

第一个示例只是部分应用唯一参数的特殊情况。但是,当您在表达式上使用下划线时,它代表匿名函数中的位置参数。

a.mapValues(_.size)
a.mapValues(x => x.size)

很容易混淆,因为它们都会导致匿名函数。其实还有第三个下划线,就是用来把方法转换成方法值(也是匿名函数),比如:

a.groupBy _

【讨论】:

    猜你喜欢
    • 2019-08-20
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 2019-07-10
    • 1970-01-01
    • 2011-12-04
    • 2018-04-23
    • 1970-01-01
    相关资源
    最近更新 更多