我遇到一个问题,()=>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)
}
Run Code Online (Sandbox Code Playgroud)
这种() => Gate转换发生在哪里unary_!?为什么它只发生?
编辑
谢谢你的回答!我提出这个问题,因为埃塔扩张(从X以() => X块为我们定义的另一个隐式转换X,并希望发生的.删除不必要的括号从unary_!解决问题的我们,谢谢!
这只是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
Run Code Online (Sandbox Code Playgroud)
第一种情况是该功能的应用.不打字检查.
第二种情况是什么?它不是隐式地添加parens以将其转换为应用程序,而是首先进行eta扩展以创建一个类型检查的函数.
有人建议首先添加parens(规范中的"空应用程序"),这样它的行为与第一种情况相同.
这是关于如何处理前缀op的规范措辞:
http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#prefix-operations
前缀操作op; e由前缀运算符op组成,前缀运算符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)
^
Run Code Online (Sandbox Code Playgroud)
在那里,您首先得到简单的评估,即6.26.2中的第一次转换.
关于相关票证的更多示例.
在链接票证上的评论不仅表明改变了隐含的顺序,而且禁止在这种情况下进行eta扩展:
考虑到预期的Function0类型,我倾向于进一步讨论eta-expansion,并避免从一开始就使用相同形状的SAM类型触发它.
这太糟糕了,因为这会成为一个不错的小益智游戏.