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