【问题标题】:Why does passing some functions in scala require _为什么在scala中传递一些函数需要_
【发布时间】:2017-06-24 10:59:59
【问题描述】:

为了更好地了解 scala,我遇到了一种我无法解释的行为。 下面的代码工作正常:

def triple(x: Double) = 3 * x
Array(3.14,1.42,3.9).map(triple)

但是,如果我在数学库中调用 scala ceil 函数,那么我需要传递一个 _ 才能使其工作

def valueAtOneQuarter(f: (Double)=> Double) = f(0.25)
valueAtOneQuarter(sqrt _)

从前面一段代码中的函数调用来看,这个上下文中的 _ 有什么特别之处。

【问题讨论】:

  • 它实际上对我来说都很好,在这两种情况下都没有下划线
  • 扩展对我也有效,并且自动发生,不需要像 Dima 所说的那样使用_。

标签: scala functional-programming


【解决方案1】:

下划线实际上扩展为一个函数。

所以sqrt _ 变成了函数a => sqrt(a)。

你会注意到这个扩展函数与 valueatonequarter 方法的参数类型 f 匹配。

在更一般的术语中,有时需要下划线来标​​记编译器以将方法(使用 def 声明的方法)转换为函数(方法和函数相似但不是一回事)。编译器会尝试自动将方法转换为函数,但在某些情况下它需要额外的指针(如显式类型声明或 _)。有关 eta 扩展和部分函数的完整说明,请参见此处:https://medium.com/@sinisalouc/on-method-invocations-or-what-exactly-is-eta-expansion-1019b37e010c

【讨论】:

  • 这并没有回答为什么在一种情况下需要下划线而在另一种情况下不需要下划线的问题。
【解决方案2】:

Scala 中的方法和函数并不相同。

你可以这样定义一个方法:

def method(x:Double):Double = ...

但是你用这种方式定义一个函数:

val func = (x: Double):Double => {...}

当您将函数作为参数传递给方法时,它必须是函数,而不是方法。

所以你必须使用下划线来从一个方法中创建一个函数。

有时 Scala 使用“Eta 扩展”功能自动将方法转换为函数。但在某些情况下,您必须手动完成

【讨论】:

  • 感谢似乎 _ 在 scala 的不同上下文中具有不同的含义。几乎就像如果有一些差距_就是答案
【解决方案3】:

回答是因为现有答案并没有真正解释何时需要_,只是“有时”或“在某些情况下”。

在 Scala 中要理解的一个非常重要的概念是预期类型。在您的第一个示例中,map 参数的预期类型是Double => B,其中包含一些未知的B;第二个是Double => Double。当期望的类型是函数类型并传递了方法名时,它会自动转换为函数。因此,正如 cmets 所说,第二个示例在没有 _ 的情况下有效。只有在没有预期类型的​​情况下才需要,比如

val f = sqrt _

方法重载时也可能出现问题,但是仅仅添加_通常也不起作用;相反,您将指定参数类型以显示使用的方法,例如max(_: Int, _: Int) 或 max(_: Double, _: Double)。

谢谢似乎_在scala的不同上下文中具有不同的含义

是的,不少:What are all the uses of an underscore in Scala?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 2011-09-20
    • 2018-07-13
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多