Gal*_*eño 3 complexity-theory scala pattern-matching
我有一个 Scala 问题。想象一下您正在构建代码来处理不同的操作,即
operation match {
case A => doA()
case B => doB()
case _ => throw new Exception("Unknown op: " + operation)
}
Run Code Online (Sandbox Code Playgroud)
现在,想象一下,稍后您想要构建一个新版本,并且想要扩展操作 C 的模式匹配。如何以操作分辨率仍然为 O(1) 的方式做到这一点?
我的意思是,我可以修改上面的代码来执行以下操作:
case _ => handleUnknownOperation(operation)
Run Code Online (Sandbox Code Playgroud)
子类可以实现handleUnknownOperation来执行以下操作:
operation match {
case C => doC()
}
Run Code Online (Sandbox Code Playgroud)
但这很糟糕,因为这意味着 C 操作需要 O(2)。
扩展这种模式匹配结构的任何其他想法或最佳实践?
干杯,高尔德
为了回答最初的问题,模式匹配被有效地转换为一系列 if/else 语句,只是一系列测试。最后case _只是一个失败(没有相关的测试)。因此,在一场比赛中拥有 A、B 和 C 以及在一场比赛中拥有 A 和 B 然后委托给另一场与 C 匹配的比赛之间没有什么区别。以下面的例子为例:
class T
case class A(v: Int) extends T
case class B(v: Int) extends T
case class C(v: Int) extends T
class Foo {
def getOperation(t: T): Unit = {
t match {
case A(2) => println("A")
case B(i) => println("B")
case _ => unknownOperation(t)
}
}
def unknownOperation(t: T): Unit = println("unknown operation t=" + t)
}
class Bar extends Foo {
override def unknownOperation(t: T): Unit = t match {
case C(i) => println("C")
case _ => println("unknown operation t=" + t)
}
}
Run Code Online (Sandbox Code Playgroud)
使用jad反编译Foo.class,我们得到:
public void getOperation(T t) {
label0:
{
T t1 = t;
if(t1 instanceof A)
{
if(((A)t1).v() == 2)
{
Predef$.MODULE$.println("A");
break label0;
}
} else
if(t1 instanceof B)
{
Predef$.MODULE$.println("B");
break label0;
}
unknownOperation(t);
}
}
Run Code Online (Sandbox Code Playgroud)
所以,我想说你不应该担心性能[*]。
然而,从设计的角度来看,我可能会稍微改变一下事情,或者像 Frank 建议的那样使用命令模式,或者unknownOperation您可以覆盖getOperation,它与 C 进行匹配,然后委托给super.getOperation(),而不是在子类中覆盖。对我来说似乎更整洁。
class Bar extends Foo {
override def getOperation(t: T): Unit = t match {
case C(i) => println("C")
case _ => super.getOperation(t)
}
}
Run Code Online (Sandbox Code Playgroud)
[*] 需要注意的是复杂性。Scala 2.10 之前的版本存在一个问题,其中模式匹配器生成的 .class 文件过于复杂(嵌套提取器生成指数空间字节码),因此如果您使用的匹配非常复杂,这可能会导致问题。这个问题在 2.10 中通过虚拟模式匹配器得到了修复。如果您遇到此问题,那么此错误的解决方法之一是将模式匹配拆分为不同的方法/类。