为什么一元运算符启用()=> X隐式转换?

时间:2015-04-23 06:19:28

标签: scala

我遇到一个问题,即在定义和使用一元运算符时会发生隐式()=>X转换。以下是一个最小的例子:

class Gate {
  def unary_!(): Gate = this
}

class Foo {
  private def foo(f: () => Gate) = 1
  val gate = new Gate

  // Compiles, -Xprint:typer shows it becomes
  //   Foo.this.foo({
  //     (() => Foo.this.gate.unary_!())
  //   })
  foo(!gate)

  // Does not compile, we get
  //  error: type mismatch;
  //  found   : Gate
  //  required: () => Gate
  //  foo(gate)
  foo(gate)
}

() => Gate转换发生在何处?为什么只发生unary_!

被修改

谢谢你的回答!我提出了这个问题,因为Eta扩展(从X() => X阻止了我们为X定义的另一个隐式转换,并希望发生。从unary_!删除不必要的括号解决了我们的问题。谢谢!

1 个答案:

答案 0 :(得分:5)

这只是eta-expansion,它将方法转换为函数。

http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#eta-expansion

触发器是期望的类型是函数。

规范中的链接不明确,但扩展为6.26.5。

比较这两种形式:

scala> foo(gate.unary_!())
<console>:11: error: type mismatch;
 found   : Gate
 required: () => Gate
              foo(gate.unary_!())
                              ^

scala> foo(gate.unary_!)
res3: Int = 1

第一种情况是该功能的应用。不打字检查。

第二种情况是什么?它不是隐式地添加parens以将其转换为应用程序,而是首先进行eta扩展以创建一个类型检查的函数。

有人建议首先添加parens(规范中的“空应用程序”),这样它的行为与第一种情况相同。

这是关于如何处理前缀op的规范措辞:

http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#prefix-operations

  

前缀操作op; e由必须的前缀运算符op组成   是标识符'+',' - ','!'或'〜'之一。表达式op; e是   等同于后缀方法应用程序e.unary_op。

但是这个例子表明它是成员选择,但不是应用程序。

以下是方法定义中没有parens的反例:

scala> class Gate { def unary_! : Gate = this }
defined class Gate

scala> def foo(f: () => Gate) = 1
foo: (f: () => Gate)Int

scala>   val gate = new Gate
gate: Gate = Gate@2db0f6b2

scala> foo(!gate)
<console>:11: error: type mismatch;
 found   : Gate
 required: () => Gate
              foo(!gate)
                  ^

首先是简单的评估,第6.26.2节中的第一次转换。

更多示例on the related ticket

链接票证上的评论建议不仅要更改隐含的顺序,还要禁用此案例的eta扩展:

  

我倾向于更进一步,弃用eta-expansion给出一个   期望的Function0类型,并避免使用SAM类型触发它   从一开始就是相同的形状。

这太糟糕了,因为这会成为一个不错的小益智游戏。