Scala多态重载方法调度导致StackOverflowError



通过玩对象层次结构来学习Scala,并得出以下结论:

trait LogItem {
  override def toString = getClass.getName
}
class LogItemOne extends LogItem {}
class LogItemTwo extends LogItem {}
class LogService {
  private def addLogItem(item: LogItemOne) = { println(item.toString) }
  private def addLogItem(item: LogItemTwo) = { println(item.toString) }
  def addLogItem[A <: LogItem] (item: A): Unit = { addLogItem(item) }
}

下面的测试导致StackOverflowError

"Log service" should "polymorphically add log item" in {
    new LogService().addLogItem(new LogItemOne())
    new LogService().addLogItem(new LogItemTwo())
}

是否有可能多态地调度到正确的addLogItem方法,而不需要LogService的客户端为特定类型的LogItem调用特定的方法?

据我所知,Scala没有对方法参数执行动态调度(与Java相同)。换句话说,您的代码不会多态地为给定的LogItem选择正确的方法。相反,由于A擦除到LogItem,它将再次递归调用addLogItem[A <: LogItem](item: A),这将导致StackOverflow

在参数上"伪造"动态分派的一种方法是使用访问者模式。然而,在这种情况下,最好的解决方案可能是使用Scala强大的match语句:

class LogService {
  private def addLogItemOne(item: LogItemOne) = { println(item.toString) }
  private def addLogItemTwo(item: LogItemTwo) = { println(item.toString) }
  def addLogItem(item: LogItem): Unit = item match {
    case one: LogItemOne => addLogItemOne(one)
    case two: LogItemTwo => addLogItemTwo(two)
  }
}

实际上,如果我删除addLogItem[A <: LogItem] (item: A): Unit方法并打开其他方法的可见性,它就可以工作了。所以从本质上讲,LogService本身就变成了一个访问者。

class LogService {
  def addLogItem(item: LogItemOne) = { println(item.toString) }
  def addLogItem(item: LogItemTwo) = { println(item.toString) }
}

相关内容

  • 没有找到相关文章

最新更新