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

时间:2015-05-16 21:40:26

标签: scala polymorphism overloading hierarchy traits

通过使用对象层次结构学习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方法?

2 个答案:

答案 0 :(得分:3)

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

对参数进行“伪造”动态调度的方法是使用visitor pattern。但是,在这种情况下,最好的解决方案可能是使用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)
  }
}

答案 1 :(得分:0)

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

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