子类型作为覆盖方法的参数

时间:2019-02-04 15:58:54

标签: scala

以下代码无法编译。为什么不能在SomeTypeString中将SomeInst作为覆盖方法的参数传递?

trait SomeType
abstract class SomeClass[T] {
  def method(someType: SomeType): Unit
}
class SomeTypeString extends SomeType

class SomeInst extends SomeClass[String]() {
  override def method(someType: SomeTypeString): Unit = ???
}

1 个答案:

答案 0 :(得分:4)

父类型的实例必须可以被子类型的实例替换,而无需更改程序的所需属性。这就是使用Liskov替代原理的“子类型”的定义,该定义给出了基于行为的基于合同的子类型概念,其中考虑了混叠。

这意味着在任何地方我都有一个SomeClass的实例,我也可以使用SomeInst的一个实例。但是,在您的示例中,这是不正确的:如果我有i的实例SomeClass,那么我可以调用i.method(s),其中s是{{1}的实例}。根据《里斯科夫替代原则》,我 当我打电话给SomeType时,必须能够做到相同,其中ii.method(s)ii的实例。但是我不被允许。我只允许传递SomeType的实例。

Ergo,您的示例违反了Liskov替换原则,换句话说,不允许SomeTypeStringSomeInst的子类型。

请注意,这实际上并不新鲜。这在1960年代就已经知道,甚至在Barbara Liskov制定LSP之前,这些只是功能的标准子类型化规则:

  • 函数的参数类型相反
  • 函数的返回类型是协变的