为什么SAM规则不适用于无参数方法

问题描述 投票:3回答:1
// ok
val sam0: MySamWithEmptyParameter = () => 100

// doesn't work
//  val sam1: MySamWithParameterless = () => 100

trait MySamWithEmptyParameter {
  def receive(): Int
}

trait MySamWithParameterless {
  def receive: Int
}

为什么sam1无法覆盖receive方法? scalac将两个特征编译为相同的代码。

abstract trait TestSAM$MySamWithEmptyParameter extends Object {
  def receive(): Int
};

abstract trait TestSAM$MySamWithParameterless extends Object {
  def receive(): Int
};
scala anonymous-class
1个回答
4
投票

SI-10555谈到了这一点。这是一个简单的设计决策,只支持显式的空参数列表,即使两者都编译为空参数列表。

The relevant part of the Specification says(强调我的):

  • 方法m必须有一个参数列表;

这确实有点尴尬,因为eta扩展适用于具有空参数列表的方法。

编辑

联系Lightbend的人。以下是Scala团队负责人Adrian Moors的回复:

最初的原因是为了保持规范简单,但也许我们应该重新审视。我同意令人惊讶的是它适用于def a(): Int,但不适用于你的例子。

在内部,根本没有定义参数列表的方法和那些(即使为空)的方法被区别对待。这导致了之前的混乱/错误 - 仅举一例:https://github.com/scala/scala-dev/issues/284

在2.13中,我们正在重新进行eta扩展(它将更积极地应用,但是 - ) - 插入将首先发生)。我们一直在这方面来回反复,但目前的想法是:

  • 0-ary方法是专门处理的:如果期望的类型是sam-等效于Function0,我们eta-expand;否则,插入()(在dotty中,你需要显式地编写(),除非该方法是java定义的) - 我仍然不确定我们是否应该在这里进行eta-expand
  • 对于所有其他arities,方法引用是eta扩展的,无论期望的类型如何(如果没有类型不匹配,这可能会在重构参数的方法时隐藏错误,但忘记在任何地方应用它们。但是,因为函数是第一个 - 类值,通过简化参考方法值来构造它们应该很容易)。

结果是我们可以弃用方法值语法(m _),因为它只是简单地编写m。 (请注意,这与占位符语法不同,如m(, _)。)(另请参阅此评论的主题:https://github.com/lampepfl/dotty/issues/2570#issuecomment-306202339

© www.soinside.com 2019 - 2024. All rights reserved.