18

我想了解为什么 eta 扩展(第 6.26.5 节)不适用于重载方法。例如,如果我有以下两种方法:

def d1(a: Int, b: Int) {}
def r[A, B](delegate: (A, B) ⇒ Unit) {}

我可以做这个:

r(d1)

但是,重载r时它将不再起作用:

def r[A, B](delegate: (A, B) ⇒ Unit) {}
def r[A, B, C](delegate: (A, B, C) ⇒ Unit) {}

r(d1) // no longer compiles

我必须将方法显式转换为部分应用的函数:

r(d1 _)

有没有办法通过显式转换来完成以下操作?

def r[A, B](delegate: (A, B) ⇒ Unit) {}
def r[A, B, C](delegate: (A, B, C) ⇒ Unit) {}

def d1(a: Int, b: Int) {}
def d2(a: Int, b: Int, c: Int) {}

r(d1) // only compiles with r(d1 _)
r(d2) // only compiles with r(d2 _)

有一些类似的问题,但没有完全解释。

4

1 回答 1

15

隐式是正确的术语,该部分是规范中的 6.26.2,这一定是一个重复的问题(或者有人会认为;这是稳定的行为)。

链接的问题还回答了预期类型必须是函数。

我会冒险说,当超载时,适用性会受到破坏,因为没有预期的类型(6.26.3,臭名昭著)。未重载时,应用 6.26.2(eta 扩展),因为参数的类型决定了预期的类型。重载时,arg 是专门键入的,没有预期的类型,因此 6.26.2 不适用;因此,任何重载的变体都不d被认为是适用的。

从 6.26.3 重载分辨率

否则,令 S 1 , . . . , S m 是通过使用未定义的预期类型键入每个参数而获得的类型向量。

当你命名一个没有参数的方法时,这里是可用的“隐式转换”(所谓的),如r(d1). 关于 eta 扩展的段落适用于此。

6.26.2 方法转换

以下四种隐式转换可以应用于未应用于某些参数列表的方法。

评估。类型 => T 的无参数方法 m 总是通过计算 m 绑定到的表达式转换为类型 T。

隐式应用。如果该方法仅采用隐式参数,则隐式参数将按照第 7.2 节的规则进行传递。

埃塔扩展。否则,如果该方法不是构造函数,并且预期类型 pt 是函数类型 (Ts ) ⇒ T ,则对表达式 e 执行 eta-expansion (§6.26.5)。

空应用程序。否则,如果 e 具有方法类型 ()T ,则将其隐式应用于空参数列表,产生 e()

更多绿色检查后解释...

以下示例演示了在存在重载的情况下首选应用程序而不是 eta 扩展。当 eta-expansion 不适用时,“空应用程序”是在 6.26.2 中尝试的最终隐式。换句话说,当重载时(从表面上看,这是令人困惑和邪恶的),按照统一访问原则很自然地采用fas ,但除非您非常确定函数类型,否则采用as是不自然或奇怪的是期待。f()ff _

scala> object Bar {
     | def r(f: () => Int) = 1
     | def r(i: Int) = 2
     | }
defined module Bar

scala> def f() = 4
f: ()Int

scala> Bar.r(f)
res4: Int = 2

scala> Bar.r(f _)
res5: Int = 1

重载分辨率的候选者通过“形状”进行预筛选。形状测试封装了从不使用 eta-expansion 的直觉,因为 args 是在没有预期类型的​​情况下键入的。这个例子表明即使 eta-expansion 是“表达式类型检查的唯一方法”,它也没有被使用。

scala> object Bar {
     | def bar(f: () => Int) = 1
     | def bar(is: Array[Int]) = 2
     | }
defined object Bar

scala> def m() = 7
m: ()Int

scala> m _
res0: () => Int = <function0>

scala> Bar.bar(m)
<console>:10: error: overloaded method value bar with alternatives:
  (is: Array[Int])Int <and>
  (f: () => Int)Int
 cannot be applied to (Int)
              Bar.bar(m)
                  ^

读到这里的任何人都会对这两个转换的相关问题感到好奇。

于 2013-06-27T04:17:10.250 回答