【发布时间】:2017-03-17 02:47:41
【问题描述】:
里氏替换原则指出
如果
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
}
如果您将PartialFunction 应用于未定义的值,您将收到异常。
在 scala 中创建PartialFunction 的一种便捷方法是使用模式匹配。这样做,您会收到未定义值的 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")
fn: String => Int =
pf: PartialFunction[String,Int] =
程序:程序[](val f: String => Int,val s: String) => (Boolean, Int)
res0: Boolean = true
scala.MatchError: 两个(属于 java.lang.String 类)
在 scala.PartialFunction$$anon$1.apply(delme.sc:249)
在 scala.PartialFunction$$anon$1.apply(delme.sc:247)
在 ...
fn 和 pf 都是 Function1 的子类型,但我不能在不更改 program 的情况下将 fn 替换为 pf。所以在我看来,这违反了 LSP。
你怎么看?
【问题讨论】:
-
这将主要是一篇评论文章。对于您所问的更一般性问题的应用或使用,您有更具体的问题吗?
-
绝对不是。我只是向其他开发人员征求意见。也许我应该把它发布到另一个社区?
-
您还可以定义一个
Function1,它只为除"one"之外的所有输入抛出异常。您违反 LSP 的论点是抛出异常可能是一种不受欢迎的改变,但Function1仍然可以有抛出异常的输入。例如BigDecimal("abc")。PartialFunction和Function1之间的主要区别在于您有一个内置的方法来检查是否首先定义了元素。 -
没有语言可以防止用户出错。如果有人想破坏他的程序,他总是可以做到的。我的担忧不仅仅是在我看来,Scala(语言本身)违反了 LSP。这永远不会让它变得不那么“酷”,但我只是想知道。
标签: scala liskov-substitution-principle