【问题标题】:Implicit method to function conversion doesn't work when passed as argument?作为参数传递时,函数转换的隐式方法不起作用?
【发布时间】:2019-09-24 12:06:13
【问题描述】:

我可能遗漏了一些东西,但我遇到了一个令人惊讶的不起作用的模式。
这里是:

object A {
  def bar(func: (Int, Int) => Int): Int = 2
  def bar(func: Int => Int): Int = 3
  def foo(func: Int => Int): Int = 4
}

def f(n: Int) : Int = n + 1
val g: Int => Int = f

A.foo(f) // works fine
A.bar(f) // doesn't work
A.bar(g) // but this works

编译器要求我显式应用方法f以便通过它(写作f _):
Unapplied methods are only converted to functions when a function type is expected.

我不明白为什么在将f 传递给A.foo 时隐式进行转换,但在传递给A.bar 时却没有。这可能与bar 有两个重载有关,但我不确定为什么?

我在 Scala 2.12.8 中使用 scalac。

【问题讨论】:

  • @francoisr 给出了正确答案,但如果您还想查看有关此问题的一些规范详细信息,请参阅this question 的答案。
  • @slouc 感谢您的链接。我将其添加到我的答案中

标签: scala


【解决方案1】:

错误消息为您指明了正确的方向:作为一个方法f 不直接等同于Int => Int 类型的值,尽管它们相似。为了将它作为参数传递,f 需要转换为一个值,这通常但并不总是隐式完成。

当您声明val g = f _ 或使用A.bar(f _) 时,您明确地将方法转换为值。

由于bar 方法被重载,编译器不确定您要将f 转换为哪种类型(是Int => Int 还是(Int,Int) => Int?)。为避免任何意外,它会要求您进行显式转换。您也可以使用A.bar(f: Int => Int) 对其进行编译,因为这样可以通过显式选择bar 定义之一来消除歧义。

编译器可能会尝试对此进行推理,因为您传递了 Int => Int 并且隐式方法->值提升只有在您打算将其提供给 bar(Int => Int) 时才会发生,但在这种情况下它只是没有吨。这可能有一个技术原因,例如编译器由于组合爆炸而没有尝试组合重载决议和隐式提升。我认为这是编译器的一个小限制,通过更明确的方式很容易绕过它。越明确越好!

@slouc 在 cmets 中链接,有关此问题的更多技术细节可在 here 获得。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-11
    • 2011-07-27
    相关资源
    最近更新 更多