`PartialFunction extends Function` 是否违反了 LSP?

ger*_*s.b 6 scala liskov-substitution-principle

Liskov 替换原则指出

如果S是 的子类型T,则类型的对象T可以替换为类型的对象,S而不会改变该程序的任何所需属性。

但是,在 Scala 中,PartialFunction并非在所有情况下都适用/定义。

trait Function1 {
  def apply(x: A): R
}

trait PartialFunction extends Function1 {
  def apply(x: A): R
  def isDefinedAt(x: A): Boolean
}
Run Code Online (Sandbox Code Playgroud)

如果将 aPartialFunction应用于未定义的值,您将收到异常。

PartialFunction在 Scala 中创建一个的方便方法是使用模式匹配。这样做,您会收到一个MatchError未定义的值。

val fn:Function1[String, Int] = s => s.length

val pf:PartialFunction[String, Int] = {
  case "one" => 3
}

def program(f:Function1[String, Int], s:String):(Boolean, Int) = (
  f.isInstanceOf[Function1[String, Int]], f(s)
)

program(fn, "one") == program(pf, "one")
program(fn, "two") == program(pf, "two")
Run Code Online (Sandbox Code Playgroud)

fn: String => Int = <function1>

pf: PartialFunction[String,Int] = <function1>

程序:program[](val f: String => Int,val s: String) => (Boolean, Int)

res0:布尔值 = 真

scala.MatchError:两个(java.lang.String 类)

   在 scala.PartialFunction$$anon$1.apply(delme.sc:249)

   在 scala.PartialFunction$$anon$1.apply(delme.sc:247)

   在 ...

这两个fnpf的亚型Function1,但我不能代替fnpf,而不会改变我的program。所以在我看来,这违反了 LSP。

你怎么认为 ?

Ale*_*nov 6

fn并且pf不是 的子类型Function1,因为它们根本不是类型。它们是值,LSP 并没有说您可以使用任何类型的对象T并将其替换为任何类型的对象SInt当然是 的子类型Int,但替换12会使正确的程序不正确。

PartialFunction[String, Int]是 的子类型Function1[String, Int],但是 的契约Function1并没有禁止apply抛出异常,实际上明确允许它:

将此函数的主体应用于参数。它可能会抛出异常。

因此,如果您的程序可以处理 type 的对象Function1[A, B],则它必须已经以apply某种方式处理抛出异常,而PartialFunction抛出 aMatchError只是一种特定情况。