【问题标题】:'Ambiguous reference to overloaded definition' when override method in derived class在派生类中覆盖方法时“对重载定义的模糊引用”
【发布时间】:2014-08-09 13:10:41
【问题描述】:

我有以下代码:

import com.github.nscala_time.time.Imports._

class Account {
    def balance(date: DateTime): Double = {
        /* some logic that calculates balance on given date */
        val calculatedBalance = 42
        calculatedBalance
    }

    def balance: Double = balance(DateTime.now)
}

class Deposit(val interestRate: Double) extends Account {
    override def balance(date: DateTime): Double = {
        /* some logic that calculates balance for deposit account */
        val calculatedBalance = 100 * interestRate;
        calculatedBalance
    }
}

我尝试通过以下方式使用这些类:

val simpleAccount = new Account
val depositAccount = new Deposit(0.1)

val simpleBalanceOnDate = simpleAccount.balance(DateTime.now + 1.month)   // A
val depositBalanceOnDate = depositAccount.balance(DateTime.now + 1.month) // B
val simpleBalance = simpleAccount.balance   // C
val depositBalance = depositAccount.balance // D

案例ABC 编译时没有任何错误,但对于D 行,我看到错误消息:

Error:(28, 38) ambiguous reference to overloaded definition,
both method balance in class Deposit of type (date: com.github.nscala_time.time.Imports.DateTime)Double
and  method balance in class Account of type => Double
match expected type ?
val depositBalance = depositAccount.balance
                                    ^

您能否解释一下为什么D 会出现编译错误以及为什么C 不会出现编译错误?

提前致谢!

【问题讨论】:

标签: scala compiler-errors overriding overloading


【解决方案1】:

我想编译器对无参数方法继承感到困惑,虽然我无法诚实地解释为什么,但对于一个快速的解决方案,这应该可以工作:

class Account {
  { ... }
  def balance(): Double = balance(DateTime.now)
}

val depositAccount = new Deposit(0.1)
val depositBalance = depositAccount.balance()

为什么会发生这种情况对我来说很模糊,也许其他人知道 scala 编译器是如何看待无参数方法继承的。

也在阅读,特别是Programming in Scala

这种无参数方法在 Scala 中很常见。相比之下,用空括号定义的方法,例如 def height(): Int,称为空括号方法。推荐的约定是在没有参数时使用无参数方法,并且该方法仅通过读取包含对象的字段来访问可变状态(特别是,它不会更改可变状态)。 该约定支持统一访问原则1,它表示客户端代码不应受到将属性实现为字段或方法的决定的影响。例如,我们可以选择将宽度和高度实现为字段而不是方法,只需将每个定义中的 def 更改为 val:

abstract class Element {
  def contents: Array[String]
  val height = contents.length
  val width = 
    if (height == 0) 0 else contents(0).length
}

从客户的角度来看,这两对定义是完全等价的。唯一的区别是字段访问可能比方法调用稍快,因为字段值是在类初始化时预先计算的,而不是在每次方法调用时计算。另一方面,字段在每个 Element 对象中都需要额外的内存空间。因此,属性是否更好地表示为字段或方法取决于类的使用配置文件,并且该使用配置文件可能会随着时间而改变。关键是 Element 类的客户端在其内部实现发生变化时不应受到影响。

【讨论】:

  • 所以在这种情况下,balance 没有副作用,所以balance 优先于balance()
  • "建议的约定是在没有参数时使用无参数方法,并且该方法仅通过读取包含对象的字段来访问可变状态" 但实际上您是无参数方法调用另一个方法,所以它不读取任何变量。
  • @EndeNeu,如果balance(date: DateTime) 仅根据包含对象的字段值计算结果(即它不读取来自数据库、配置、不发出 Web 请求等的任何内容)。无论如何,这只是一个品味问题。我已经为该问题使用了解决方法,但问题仍然存在,因为我很感兴趣为什么编译器会按照我描述的方式运行?
  • 当然不是,我不是说它是无效的语法,我只是说按照书上无参方法应该访问类成员变量,在你的实现中,即使函数没有' t 真的做任何事情,严格来说它仍然是一个函数,我只是建议无参数的balance 也应该被感知。也就是说,这只是我的 2 美分,我也认为这是 Scala 编译器的错误,因为您的语法非常好,.
【解决方案2】:

为什么不提供这样的默认参数:

    class Account {
    def balance(date: DateTime = DateTime.now): Double = {
        /* some logic that calculates balance on given date */
        val calculatedBalance = 42
        calculatedBalance
    }
}

class Deposit(val interestRate: Double) extends Account {
    override def balance(date: DateTime): Double = {
        /* some logic that calculates balance for deposit account */
        val calculatedBalance = 100 * interestRate;
        calculatedBalance
    }
}

val simpleBalanceOnDate = simpleAccount.balance(1)   // A
    val depositBalanceOnDate = depositAccount.balance(1) // B
    val simpleBalance = simpleAccount.balance()   // C
    val depositBalance = depositAccount.balance() // D

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 2011-06-01
    相关资源
    最近更新 更多